mirror of
https://github.com/emilybache/GildedRose-Refactoring-Kata.git
synced 2026-02-18 07:51:29 +00:00
feat: add everything
This commit is contained in:
parent
c12f213cd0
commit
6af42870e9
BIN
react-typescript/public/seeding.png
Normal file
BIN
react-typescript/public/seeding.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@ -1,39 +0,0 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import { createGlobalStyle } from 'styled-components';
|
||||
import ItemsSection from './ItemsSection';
|
||||
import Header from './Header';
|
||||
|
||||
function App(): JSX.Element {
|
||||
|
||||
@ -9,15 +10,14 @@ function App(): JSX.Element {
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;500&family=Ubuntu:wght@300;400;500;700&display=swap');
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: RGB(255, 255, 253);
|
||||
color: RGB(227, 226, 215);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
text-align: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
@ -26,7 +26,7 @@ function App(): JSX.Element {
|
||||
return (
|
||||
<section>
|
||||
<GlobalStyle />
|
||||
{/* <Header /> */}
|
||||
<Header />
|
||||
<ItemsSection />
|
||||
</section>
|
||||
);
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import useDayLoader from '../hooks/useDayLoader';
|
||||
import styled from 'styled-components';
|
||||
|
||||
//TODO: define styled components here
|
||||
|
||||
function Button() {
|
||||
const Button = styled(motion.button)`
|
||||
border: none;
|
||||
|
||||
`
|
||||
|
||||
const { loadNextDay } = useDayLoader();
|
||||
return (
|
||||
<Button onClick={loadNextDay}>Next Day</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default Button;
|
||||
18
react-typescript/src/components/Conjured.tsx
Normal file
18
react-typescript/src/components/Conjured.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import styled from "styled-components";
|
||||
import {motion} from 'framer-motion';
|
||||
|
||||
function Conjured(value: boolean, index: number): JSX.Element {
|
||||
const Conjured = styled(motion.span)`
|
||||
role: 'region';
|
||||
`;
|
||||
|
||||
return (
|
||||
<Conjured
|
||||
key={index}
|
||||
>
|
||||
{value ? "✅" : "❌"}
|
||||
</Conjured>
|
||||
);
|
||||
}
|
||||
|
||||
export default Conjured;
|
||||
34
react-typescript/src/components/Header.tsx
Normal file
34
react-typescript/src/components/Header.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
function Header(): JSX.Element {
|
||||
const Nav = styled.nav`
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
justify-content: center;
|
||||
font-size: 1rem;
|
||||
align-items: center;
|
||||
height: 10vh;
|
||||
border-bottom: 1px solid RGB(12, 16, 36);
|
||||
margin-bottom: 2rem;
|
||||
span {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
font-family: 'Ubuntu', sans-serif;
|
||||
color: RGB(12, 16, 36);
|
||||
}
|
||||
img {
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
}
|
||||
`
|
||||
return (
|
||||
<Nav>
|
||||
<span>
|
||||
<img src='https://i.postimg.cc/52nKHG6q/seeding.png' alt='Gilded Rose Logo'></img>
|
||||
<p>Gilded Rose</p>
|
||||
</span>
|
||||
</Nav>
|
||||
);
|
||||
}
|
||||
|
||||
export default Header;
|
||||
@ -1,24 +1,27 @@
|
||||
import styled from "styled-components";
|
||||
import ItemsTable from './ItemsTable';
|
||||
import Button from './Button';
|
||||
import useTableController from "../hooks/useTableController";
|
||||
import TableHeader from "./TableHeader";
|
||||
|
||||
function ItemsSection(): JSX.Element {
|
||||
const ItemsSection = styled.section`
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
height: 80vh;
|
||||
flex-flow: column wrap;
|
||||
justify-content: center;
|
||||
justify-content: flex-start;
|
||||
margin: 0 5%;
|
||||
border: 1px solid RGB(12, 16, 36);
|
||||
border-radius: 10px;
|
||||
role: 'region';
|
||||
text-align: left;
|
||||
`;
|
||||
|
||||
const { columns, data } = useTableController();
|
||||
|
||||
return (
|
||||
<ItemsSection>
|
||||
<TableHeader />
|
||||
<ItemsTable columns={columns} data={data} />
|
||||
<Button />
|
||||
</ItemsSection>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,41 +1,57 @@
|
||||
import { useTable } from "react-table";
|
||||
import { usePagination, useTable } from "react-table";
|
||||
import styled from "styled-components";
|
||||
import { TTable } from "../types";
|
||||
|
||||
function ItemTable({ columns, data }: TTable): JSX.Element {
|
||||
const ItemsTable = styled.table`
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;500&family=Ubuntu:wght@300;400;500&display=swap');
|
||||
height: 60%;
|
||||
border: 1px solid RGB(12, 16, 36);
|
||||
border-radius: 10px;
|
||||
min-height: 30%;
|
||||
const ItemsTable = styled.section`
|
||||
height: 80%;
|
||||
color: RGB(12, 16, 36);
|
||||
th, td, tr {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
table {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
th, td, tr, thead, {
|
||||
outline: none;
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
p {
|
||||
padding: .5rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
|
||||
.data {
|
||||
height: 10%;
|
||||
font-weight: 300;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
th {
|
||||
font-weight: 300;
|
||||
background-color: RGB(245, 245, 243);
|
||||
font-size: .9rem;
|
||||
font-weight: 800;
|
||||
height: 5%;
|
||||
}
|
||||
|
||||
td {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
tr {
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
tr:nth-child(n):hover {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
tr:nth-child(2n + 1) {
|
||||
tr:nth-child(2n) {
|
||||
background-color: RGB(245, 245, 243);
|
||||
}
|
||||
`;
|
||||
|
||||
function ItemTable({ columns, data }: TTable): JSX.Element {
|
||||
|
||||
const {
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
@ -45,70 +61,44 @@ th, td, tr {
|
||||
} = useTable({
|
||||
columns,
|
||||
data,
|
||||
});
|
||||
}, usePagination);
|
||||
|
||||
return (
|
||||
<ItemsTable {...getTableProps()}>
|
||||
|
||||
<thead className="header">
|
||||
|
||||
{headerGroups.map(headerGroup => (
|
||||
|
||||
<tr>
|
||||
|
||||
{headerGroup.headers.map(column => (
|
||||
|
||||
<th {...column.getHeaderProps()}>
|
||||
{column.render('Header')}
|
||||
</th>
|
||||
|
||||
<table>
|
||||
<thead className="header">
|
||||
{headerGroups.map(headerGroup => (
|
||||
<tr>
|
||||
{
|
||||
headerGroup.headers.map(column => (
|
||||
<th {...column.getHeaderProps()}>
|
||||
<p>{column.render('Header')}</p>
|
||||
</th>
|
||||
))
|
||||
}
|
||||
</tr>
|
||||
))}
|
||||
|
||||
</tr>
|
||||
|
||||
))}
|
||||
|
||||
</thead>
|
||||
|
||||
<tbody {...getTableBodyProps()}>
|
||||
|
||||
{rows.map(row => {
|
||||
|
||||
prepareRow(row)
|
||||
|
||||
return (
|
||||
|
||||
<tr {...row.getRowProps()}>
|
||||
|
||||
{row.cells.map(cell => {
|
||||
|
||||
return (
|
||||
|
||||
<td
|
||||
|
||||
{...cell.getCellProps()}
|
||||
</thead>
|
||||
|
||||
|
||||
>
|
||||
|
||||
{cell.render('Cell')}
|
||||
|
||||
</td>
|
||||
|
||||
<tbody {...getTableBodyProps()}>
|
||||
{rows.map(row => {
|
||||
prepareRow(row)
|
||||
return (
|
||||
<tr {...row.getRowProps()}>
|
||||
{row.cells.map(cell => {
|
||||
return (
|
||||
<td {...cell.getCellProps()} className="data">
|
||||
<p>{cell.render('Cell')}</p>
|
||||
</td>
|
||||
)
|
||||
})}
|
||||
</tr>
|
||||
)
|
||||
|
||||
})}
|
||||
|
||||
</tr>
|
||||
|
||||
)
|
||||
|
||||
})}
|
||||
|
||||
</tbody>
|
||||
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</ItemsTable>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export default ItemTable;
|
||||
28
react-typescript/src/components/Quality.tsx
Normal file
28
react-typescript/src/components/Quality.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import styled from "styled-components";
|
||||
|
||||
function qualityBackgroundColorHSL(value: number): string {
|
||||
const hue = Math.round((value / 50) * 360);
|
||||
return `hsl(${hue}, 100%, 80%)`;
|
||||
}
|
||||
|
||||
function Quality(value: number, index: number): JSX.Element {
|
||||
const Quality = styled(motion.span)`
|
||||
role: 'region';
|
||||
font-size: 1rem;
|
||||
padding: .4rem;
|
||||
border-radius: 10px;
|
||||
color: RGB(12, 16, 36);
|
||||
background-color: ${qualityBackgroundColorHSL(value)};
|
||||
`;
|
||||
|
||||
return (
|
||||
<Quality
|
||||
key={index}
|
||||
>
|
||||
{value}
|
||||
</Quality>
|
||||
);
|
||||
}
|
||||
|
||||
export default Quality;
|
||||
19
react-typescript/src/components/SellIn.tsx
Normal file
19
react-typescript/src/components/SellIn.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import styled from "styled-components";
|
||||
import {motion} from 'framer-motion';
|
||||
|
||||
function SellIn(value: number, index: number): JSX.Element {
|
||||
const SellIn = styled(motion.span)`
|
||||
role: 'region';
|
||||
`;
|
||||
|
||||
return (
|
||||
<SellIn
|
||||
key={index}
|
||||
>
|
||||
{Math.abs(value)}
|
||||
{ value < 0 ? " Days Passed": ""}
|
||||
</SellIn>
|
||||
);
|
||||
}
|
||||
|
||||
export default SellIn;
|
||||
71
react-typescript/src/components/TableHeader.tsx
Normal file
71
react-typescript/src/components/TableHeader.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import styled from 'styled-components';
|
||||
import useAllItems from '../hooks/useAllItems';
|
||||
import useDayLoader from '../hooks/useDayLoader';
|
||||
|
||||
function TableHeader() {
|
||||
const Button = styled(motion.button)`
|
||||
border: 1px solid RGB(12, 16, 36);
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: RGB(12, 16, 36);
|
||||
color: RGB(245, 245, 243);
|
||||
margin: 0 1%;
|
||||
height: 80%;
|
||||
`
|
||||
const Header = styled(motion.span)`
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 300;
|
||||
padding: .5rem;
|
||||
border-bottom: 1px solid RGB(12, 16, 36);
|
||||
height: 10%;
|
||||
`
|
||||
const HeaderText = styled(motion.span)`
|
||||
display: flex;
|
||||
flex-flow: column no-wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
padding: .5rem;
|
||||
color: RGB(12, 16, 36);
|
||||
`
|
||||
|
||||
const ItemsBadge = styled(motion.span)`
|
||||
align-self: center;
|
||||
font-size: 1rem;
|
||||
padding: .2rem;
|
||||
margin: 0 8%;
|
||||
background-color: RGB(149, 154, 163);
|
||||
color: RGB(245, 245, 243);
|
||||
border: 1px solid RGB(149, 154, 163);
|
||||
border-radius: 5px;
|
||||
`
|
||||
|
||||
const { loadNextDay } = useDayLoader();
|
||||
const {items} = useAllItems();
|
||||
const count = items.length;
|
||||
return (
|
||||
<Header>
|
||||
<HeaderText>
|
||||
Items
|
||||
<ItemsBadge>
|
||||
{count}
|
||||
</ItemsBadge>
|
||||
</HeaderText>
|
||||
<Button
|
||||
onClick={loadNextDay}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
>
|
||||
Next Day →
|
||||
</Button>
|
||||
</Header>
|
||||
);
|
||||
}
|
||||
|
||||
export default TableHeader;
|
||||
@ -1,8 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const ButtonSectionStyle = styled.section`
|
||||
width: 100%;
|
||||
height: 20%;
|
||||
`
|
||||
|
||||
export default ButtonSectionStyle;
|
||||
@ -1,8 +0,0 @@
|
||||
import { css } from 'styled-components';
|
||||
|
||||
const ButtonStyle = css`
|
||||
width: 1%;
|
||||
height: 2%;
|
||||
`
|
||||
|
||||
export default ButtonStyle;
|
||||
@ -1,24 +0,0 @@
|
||||
import { createGlobalStyle } from "styled-components";
|
||||
|
||||
const GlobalStyle = createGlobalStyle`
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
background-color: RGB(132, 151, 149);
|
||||
color: RGB(227, 226, 215);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
text-align: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
`
|
||||
|
||||
export default GlobalStyle;
|
||||
@ -1,26 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
const ItemsStyle = styled.div`
|
||||
height: 85vh;
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: white;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
li {
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
height: 10%;
|
||||
width: 40%;
|
||||
border: 1px solid white;
|
||||
margin: 3% 3%;
|
||||
}
|
||||
`;
|
||||
|
||||
export default ItemsStyle;
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import ButtonSectionStyle from './ButtonSectionStyle';
|
||||
import ButtonStyle from './ButtonStyle';
|
||||
import GlobalStyle from './GlobalStyle';
|
||||
import ItemsStyle from './ItemsStyle';
|
||||
|
||||
const styles = {
|
||||
ButtonSectionStyle,
|
||||
ButtonStyle,
|
||||
GlobalStyle,
|
||||
ItemsStyle
|
||||
}
|
||||
|
||||
export default styles;
|
||||
@ -1,6 +1,9 @@
|
||||
import { useMemo } from "react";
|
||||
import { useStore } from "../model";
|
||||
import { TTable } from "../types";
|
||||
import Conjured from "../components/Conjured";
|
||||
import Quality from "../components/Quality";
|
||||
import SellIn from "../components/SellIn";
|
||||
|
||||
function useTableController(): TTable {
|
||||
const { state } = useStore();
|
||||
@ -8,28 +11,38 @@ function useTableController(): TTable {
|
||||
|
||||
const data = useMemo(() => items, [items]);
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
Header: "Items",
|
||||
columns: [
|
||||
{
|
||||
Header: 'Name',
|
||||
accessor: 'name',
|
||||
|
||||
},
|
||||
{
|
||||
Header: 'Conjured',
|
||||
accessor: 'isConjured',
|
||||
Cell: ({ cell: { value } }: any) => { return value ? 'Yes' : 'No' },
|
||||
Cell: ({ cell: { value }, index}: any) => (
|
||||
{
|
||||
...Conjured(value, index),
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Quality',
|
||||
accessor: 'quality'
|
||||
accessor: 'quality',
|
||||
Cell: ({ cell: { value }, index}: any) => (
|
||||
{
|
||||
...Quality(value, index),
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Days Left',
|
||||
accessor: 'sellIn'
|
||||
}
|
||||
],
|
||||
},
|
||||
Header: 'Remaining Days',
|
||||
accessor: 'sellIn',
|
||||
Cell: ({ cell: { value }, index}: any) => (
|
||||
{
|
||||
...SellIn(value, index),
|
||||
}
|
||||
),
|
||||
},
|
||||
], []);
|
||||
|
||||
return {
|
||||
|
||||
@ -4,7 +4,7 @@ type TItem = {
|
||||
name: string,
|
||||
sellIn: number,
|
||||
quality: number,
|
||||
isConjured: boolean
|
||||
isConjured: boolean,
|
||||
}
|
||||
|
||||
type TProps = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user