diff --git a/README.md b/README.md
index e399c98..0878b93 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,24 @@
# chipstackoverflow
-This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app).
+Next.js application
-## Getting Started
+## Development
-First, run the development server:
+After `npm install`, you can hit `npm run dev` to start development server out-of-the-box.
-```bash
+```
+npm install
npm run dev
-# or
-yarn dev
```
+## Deployment
+
+
+
+## Application Architecture
+
+
+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
diff --git a/assets/cards/2c.svg b/assets/cards/2c.svg
new file mode 100644
index 0000000..bd352ac
--- /dev/null
+++ b/assets/cards/2c.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/2d.svg b/assets/cards/2d.svg
new file mode 100644
index 0000000..fb82541
--- /dev/null
+++ b/assets/cards/2d.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/2h.svg b/assets/cards/2h.svg
new file mode 100644
index 0000000..75e4401
--- /dev/null
+++ b/assets/cards/2h.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/2s.svg b/assets/cards/2s.svg
new file mode 100644
index 0000000..9377cf0
--- /dev/null
+++ b/assets/cards/2s.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/3c.svg b/assets/cards/3c.svg
new file mode 100644
index 0000000..4a9351e
--- /dev/null
+++ b/assets/cards/3c.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/3d.svg b/assets/cards/3d.svg
new file mode 100644
index 0000000..1140369
--- /dev/null
+++ b/assets/cards/3d.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/3h.svg b/assets/cards/3h.svg
new file mode 100644
index 0000000..f97ee53
--- /dev/null
+++ b/assets/cards/3h.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/3s.svg b/assets/cards/3s.svg
new file mode 100644
index 0000000..d256393
--- /dev/null
+++ b/assets/cards/3s.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/4c.svg b/assets/cards/4c.svg
new file mode 100644
index 0000000..a5763cd
--- /dev/null
+++ b/assets/cards/4c.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/4d.svg b/assets/cards/4d.svg
new file mode 100644
index 0000000..3924e8a
--- /dev/null
+++ b/assets/cards/4d.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/4h.svg b/assets/cards/4h.svg
new file mode 100644
index 0000000..907b967
--- /dev/null
+++ b/assets/cards/4h.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/4s.svg b/assets/cards/4s.svg
new file mode 100644
index 0000000..57a44eb
--- /dev/null
+++ b/assets/cards/4s.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/5c.svg b/assets/cards/5c.svg
new file mode 100644
index 0000000..1e0974c
--- /dev/null
+++ b/assets/cards/5c.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/5d.svg b/assets/cards/5d.svg
new file mode 100644
index 0000000..b3c599b
--- /dev/null
+++ b/assets/cards/5d.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/5h.svg b/assets/cards/5h.svg
new file mode 100644
index 0000000..879d22d
--- /dev/null
+++ b/assets/cards/5h.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/5s.svg b/assets/cards/5s.svg
new file mode 100644
index 0000000..fb54f73
--- /dev/null
+++ b/assets/cards/5s.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/6c.svg b/assets/cards/6c.svg
new file mode 100644
index 0000000..5496750
--- /dev/null
+++ b/assets/cards/6c.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/6d.svg b/assets/cards/6d.svg
new file mode 100644
index 0000000..c698b02
--- /dev/null
+++ b/assets/cards/6d.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/6h.svg b/assets/cards/6h.svg
new file mode 100644
index 0000000..8e5fe90
--- /dev/null
+++ b/assets/cards/6h.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/6s.svg b/assets/cards/6s.svg
new file mode 100644
index 0000000..5fe049b
--- /dev/null
+++ b/assets/cards/6s.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/7c.svg b/assets/cards/7c.svg
new file mode 100644
index 0000000..baa38d0
--- /dev/null
+++ b/assets/cards/7c.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/7d.svg b/assets/cards/7d.svg
new file mode 100644
index 0000000..1cd8e29
--- /dev/null
+++ b/assets/cards/7d.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/7h.svg b/assets/cards/7h.svg
new file mode 100644
index 0000000..6aab238
--- /dev/null
+++ b/assets/cards/7h.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/7s.svg b/assets/cards/7s.svg
new file mode 100644
index 0000000..58057cb
--- /dev/null
+++ b/assets/cards/7s.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/8c.svg b/assets/cards/8c.svg
new file mode 100644
index 0000000..b8d0f8c
--- /dev/null
+++ b/assets/cards/8c.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/8d.svg b/assets/cards/8d.svg
new file mode 100644
index 0000000..c748ead
--- /dev/null
+++ b/assets/cards/8d.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/8h.svg b/assets/cards/8h.svg
new file mode 100644
index 0000000..24f8a4f
--- /dev/null
+++ b/assets/cards/8h.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/8s.svg b/assets/cards/8s.svg
new file mode 100644
index 0000000..c449ba7
--- /dev/null
+++ b/assets/cards/8s.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/9c.svg b/assets/cards/9c.svg
new file mode 100644
index 0000000..b8e0496
--- /dev/null
+++ b/assets/cards/9c.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/9d.svg b/assets/cards/9d.svg
new file mode 100644
index 0000000..98c9cd6
--- /dev/null
+++ b/assets/cards/9d.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/9h.svg b/assets/cards/9h.svg
new file mode 100644
index 0000000..0614355
--- /dev/null
+++ b/assets/cards/9h.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/9s.svg b/assets/cards/9s.svg
new file mode 100644
index 0000000..8e87ea2
--- /dev/null
+++ b/assets/cards/9s.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Ac.svg b/assets/cards/Ac.svg
new file mode 100644
index 0000000..0f73aae
--- /dev/null
+++ b/assets/cards/Ac.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Ad.svg b/assets/cards/Ad.svg
new file mode 100644
index 0000000..c792298
--- /dev/null
+++ b/assets/cards/Ad.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Ah.svg b/assets/cards/Ah.svg
new file mode 100644
index 0000000..cc07d2e
--- /dev/null
+++ b/assets/cards/Ah.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/As.svg b/assets/cards/As.svg
new file mode 100644
index 0000000..71f3bbe
--- /dev/null
+++ b/assets/cards/As.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Jc.svg b/assets/cards/Jc.svg
new file mode 100644
index 0000000..c1cfee8
--- /dev/null
+++ b/assets/cards/Jc.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Jd.svg b/assets/cards/Jd.svg
new file mode 100644
index 0000000..9915646
--- /dev/null
+++ b/assets/cards/Jd.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Jh.svg b/assets/cards/Jh.svg
new file mode 100644
index 0000000..afbb14f
--- /dev/null
+++ b/assets/cards/Jh.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Js.svg b/assets/cards/Js.svg
new file mode 100644
index 0000000..0207a92
--- /dev/null
+++ b/assets/cards/Js.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Kc.svg b/assets/cards/Kc.svg
new file mode 100644
index 0000000..852d4fe
--- /dev/null
+++ b/assets/cards/Kc.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Kd.svg b/assets/cards/Kd.svg
new file mode 100644
index 0000000..441bc1b
--- /dev/null
+++ b/assets/cards/Kd.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Kh.svg b/assets/cards/Kh.svg
new file mode 100644
index 0000000..c2bfb1b
--- /dev/null
+++ b/assets/cards/Kh.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Ks.svg b/assets/cards/Ks.svg
new file mode 100644
index 0000000..7d4a0a4
--- /dev/null
+++ b/assets/cards/Ks.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Qc.svg b/assets/cards/Qc.svg
new file mode 100644
index 0000000..89a4953
--- /dev/null
+++ b/assets/cards/Qc.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Qd.svg b/assets/cards/Qd.svg
new file mode 100644
index 0000000..963322b
--- /dev/null
+++ b/assets/cards/Qd.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Qh.svg b/assets/cards/Qh.svg
new file mode 100644
index 0000000..b2c4edf
--- /dev/null
+++ b/assets/cards/Qh.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Qs.svg b/assets/cards/Qs.svg
new file mode 100644
index 0000000..8308d1e
--- /dev/null
+++ b/assets/cards/Qs.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Tc.svg b/assets/cards/Tc.svg
new file mode 100644
index 0000000..84fd438
--- /dev/null
+++ b/assets/cards/Tc.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Td.svg b/assets/cards/Td.svg
new file mode 100644
index 0000000..6a368bb
--- /dev/null
+++ b/assets/cards/Td.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Th.svg b/assets/cards/Th.svg
new file mode 100644
index 0000000..58b9a56
--- /dev/null
+++ b/assets/cards/Th.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/cards/Ts.svg b/assets/cards/Ts.svg
new file mode 100644
index 0000000..32f95f2
--- /dev/null
+++ b/assets/cards/Ts.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/assets/post-ogp-image-template.png b/assets/post-ogp-image-template.png
new file mode 100644
index 0000000..e609f18
Binary files /dev/null and b/assets/post-ogp-image-template.png differ
diff --git a/components/AnswerCard/AnswerCardCommentForm.tsx b/components/AnswerCard/AnswerCardCommentForm.tsx
index 9335561..1ae0944 100644
--- a/components/AnswerCard/AnswerCardCommentForm.tsx
+++ b/components/AnswerCard/AnswerCardCommentForm.tsx
@@ -1,124 +1,25 @@
import * as React from "react";
-import styled from "styled-components";
-import Avatar from "@@/components/Avatar";
-import Button from "@@/components/Button";
-import { LoadingIcon, SendIcon } from "@@/components/Icon";
-import TextArea from "@@/components/TextArea";
-import User from "@@/models/UserProfile";
+import MultilineTextSubmissionForm, {
+ MultilineTextSubmissionFormProps,
+} from "@@/components/MultilineTextSubmissionForm";
-export interface Props extends React.Attributes {
- user: User;
- defaultValue?: string;
- submitting?: boolean;
- invalid?: boolean;
- invalidReason?: string;
- onChange?: (e: React.ChangeEvent, body: string) => void;
- onSubmit?: (e: React.SyntheticEvent, body: string) => void;
- className?: string;
- style?: React.CSSProperties;
-}
+export type Props = MultilineTextSubmissionFormProps;
/**
* A part of `` that represents to create a new comment.
*/
export default function AnswerCardCommentForm({
- user,
- defaultValue = "",
- submitting,
- invalid,
- invalidReason,
- onChange = () => undefined,
- onSubmit = () => undefined,
+ placeholder = "What do you think?",
+ buttonLabel = "Leave a comment",
+ submittingButtonLabel = "Sending...",
...props
}: Props) {
- const [textAreaId, setTextAreaId] = React.useState(Math.random());
- const [body, setBody] = React.useState(defaultValue);
- const onBodyChange = React.useCallback(
- (e: React.ChangeEvent) => {
- setBody(e.currentTarget.value);
- onChange(e, e.currentTarget.value);
- },
- [onChange]
- );
- const onSubmitClick = React.useCallback(
- (e: React.MouseEvent) => {
- setBody("");
- setTextAreaId(Math.random());
- onSubmit(e, body);
- },
- [onSubmit, body]
- );
-
return (
-
-
-
-
- {user.name}
-
-
- <_TextArea
- placeholder="Leave your comment ..."
- defaultValue={defaultValue}
- disabled={submitting}
- onChange={onBodyChange}
- key={textAreaId}
- />
-
- {invalidReason ? {invalidReason} : null}
-
-
- {submitting ? : }
-
- {submitting ? "Submitting..." : "Submit"}
-
-
+
);
}
-
-const Root = styled.div`
- display: grid;
- grid-template-columns: 64px 1fr;
- grid-template-areas: "author author author" ". textarea textarea" ". helpful-message submit-button";
-`;
-
-const Author = styled.div`
- grid-area: author;
- display: grid;
- grid-template-columns: auto auto;
- grid-template-areas: "avatar name";
- justify-content: flex-start;
- align-items: center;
- column-gap: 16px;
-`;
-
-const AuthorAvatar = styled(Avatar)`
- grid-area: avatar;
- width: 48px;
- height: 48px;
-`;
-
-const AuthorName = styled.div`
- grid-area: name;
- font-size: 16px;
- font-weight: 700;
-`;
-
-const _TextArea = styled(TextArea)`
- grid-area: textarea;
-`;
-
-const HelpfulMessage = styled.div`
- grid-area: helpful-message;
- margin-top: 16px;
- padding-right: 16px;
- color: #576574;
- font-size: 12px;
- line-height: 1.333;
-`;
-
-const SubmitButton = styled(Button)`
- grid-area: submit-button;
- justify-self: flex-end;
- margin-top: 16px;
-`;
diff --git a/components/Illustration/Illustration.stories.tsx b/components/Illustration/Illustration.stories.tsx
new file mode 100644
index 0000000..27c9ba2
--- /dev/null
+++ b/components/Illustration/Illustration.stories.tsx
@@ -0,0 +1,9 @@
+import * as React from "react";
+import { Void } from "@@/components/Illustration";
+
+export default {
+ title: "Illustration",
+ component: Void,
+};
+
+export const v0id = () => ;
diff --git a/components/Illustration/Void.tsx b/components/Illustration/Void.tsx
new file mode 100644
index 0000000..3070da9
--- /dev/null
+++ b/components/Illustration/Void.tsx
@@ -0,0 +1,70 @@
+import * as React from "react";
+
+interface Props extends React.Attributes {
+ className?: string;
+ style?: React.CSSProperties;
+}
+
+/**
+ * Write a description here.
+ */
+export default function Void({ ...props }: Props) {
+ return (
+
+ );
+}
diff --git a/components/Illustration/index.ts b/components/Illustration/index.ts
new file mode 100644
index 0000000..5a62ba3
--- /dev/null
+++ b/components/Illustration/index.ts
@@ -0,0 +1 @@
+export { default as Void } from "./Void";
diff --git a/components/MultilineTextSubmissionForm/MultilineTextSubmissionForm.stories.tsx b/components/MultilineTextSubmissionForm/MultilineTextSubmissionForm.stories.tsx
new file mode 100644
index 0000000..a2df870
--- /dev/null
+++ b/components/MultilineTextSubmissionForm/MultilineTextSubmissionForm.stories.tsx
@@ -0,0 +1,70 @@
+import { action } from "@storybook/addon-actions";
+import * as React from "react";
+import MultilineTextSubmissionForm from "@@/components/MultilineTextSubmissionForm";
+import { text } from "@storybook/addon-knobs";
+
+export default {
+ title: "MultilineTextSubmissionForm",
+ component: MultilineTextSubmissionForm,
+};
+
+export const example = () => {
+ const [isSubmitting, setSubmitting] = React.useState(false);
+
+ return (
+ {
+ action("onSubmit")(...args);
+
+ setSubmitting(true);
+
+ setTimeout(() => {
+ setSubmitting(false);
+ }, 3000);
+ }}
+ />
+ );
+};
+
+export const submitting = () => (
+
+);
+
+export const invalid = () => (
+
+);
diff --git a/components/MultilineTextSubmissionForm/MultilineTextSubmissionForm.tsx b/components/MultilineTextSubmissionForm/MultilineTextSubmissionForm.tsx
new file mode 100644
index 0000000..0013497
--- /dev/null
+++ b/components/MultilineTextSubmissionForm/MultilineTextSubmissionForm.tsx
@@ -0,0 +1,133 @@
+import * as React from "react";
+import styled from "styled-components";
+import Avatar from "@@/components/Avatar";
+import Button from "@@/components/Button";
+import { LoadingIcon, SendIcon } from "@@/components/Icon";
+import TextArea from "@@/components/TextArea";
+import User from "@@/models/UserProfile";
+
+export interface Props extends React.Attributes {
+ user: User;
+ placeholder?: string;
+ defaultValue?: string;
+ buttonLabel?: string;
+ submittingButtonLabel?: string;
+ submitting?: boolean;
+ invalid?: boolean;
+ invalidReason?: string;
+ onChange?: (e: React.ChangeEvent, body: string) => void;
+ onSubmit?: (e: React.SyntheticEvent, body: string) => void;
+ className?: string;
+ style?: React.CSSProperties;
+}
+
+/**
+ * An UI component that offers to submit multiline text
+ */
+export default function MultilineTextSubmissionForm({
+ user,
+ placeholder = "",
+ defaultValue = "",
+ buttonLabel = "Submit",
+ submittingButtonLabel = "Submitting...",
+ submitting,
+ invalid,
+ invalidReason,
+ onChange = () => undefined,
+ onSubmit = () => undefined,
+ ...props
+}: Props) {
+ const [textAreaId, setTextAreaId] = React.useState(Math.random());
+ const [body, setBody] = React.useState(defaultValue);
+
+ const onBodyChange = React.useCallback(
+ (e: React.ChangeEvent) => {
+ setBody(e.currentTarget.value);
+ onChange(e, e.currentTarget.value);
+ },
+ [onChange]
+ );
+
+ const onSubmitClick = React.useCallback(
+ (e: React.MouseEvent) => {
+ setBody("");
+ setTextAreaId(Math.random());
+ onSubmit(e, body);
+ },
+ [onSubmit, body]
+ );
+
+ return (
+
+
+
+
+ {user.name}
+
+
+ <_TextArea
+ placeholder={placeholder}
+ defaultValue={defaultValue}
+ disabled={submitting}
+ onChange={onBodyChange}
+ key={textAreaId}
+ />
+
+ {invalidReason ? {invalidReason} : null}
+
+
+ {submitting ? : }
+
+ {submitting ? submittingButtonLabel : buttonLabel}
+
+
+ );
+}
+
+const Root = styled.div`
+ display: grid;
+ grid-template-columns: 64px 1fr;
+ grid-template-areas: "author author author" ". textarea textarea" ". helpful-message submit-button";
+`;
+
+const Author = styled.div`
+ grid-area: author;
+ display: grid;
+ grid-template-columns: auto auto;
+ grid-template-areas: "avatar name";
+ justify-content: flex-start;
+ align-items: center;
+ column-gap: 16px;
+`;
+
+const AuthorAvatar = styled(Avatar)`
+ grid-area: avatar;
+ width: 48px;
+ height: 48px;
+ user-select: none;
+`;
+
+const AuthorName = styled.div`
+ grid-area: name;
+ font-size: 16px;
+ font-weight: 700;
+ user-select: none;
+`;
+
+const _TextArea = styled(TextArea)`
+ grid-area: textarea;
+`;
+
+const HelpfulMessage = styled.div`
+ grid-area: helpful-message;
+ margin-top: 16px;
+ padding-right: 16px;
+ color: #576574;
+ font-size: 12px;
+`;
+
+const SubmitButton = styled(Button)`
+ grid-area: submit-button;
+ justify-self: flex-end;
+ margin-top: 16px;
+`;
diff --git a/components/MultilineTextSubmissionForm/index.ts b/components/MultilineTextSubmissionForm/index.ts
new file mode 100644
index 0000000..d8c2c07
--- /dev/null
+++ b/components/MultilineTextSubmissionForm/index.ts
@@ -0,0 +1,5 @@
+export { default } from "./MultilineTextSubmissionForm";
+// export type { Props as MultilineTextSubmissionFormProps } from "./MultilineTextSubmissionForm";
+
+import { Props } from "./MultilineTextSubmissionForm";
+export type MultilineTextSubmissionFormProps = Props;
diff --git a/components/PostTable/PostTable.stories.tsx b/components/PostTable/PostTable.stories.tsx
new file mode 100644
index 0000000..b0ef2e7
--- /dev/null
+++ b/components/PostTable/PostTable.stories.tsx
@@ -0,0 +1,360 @@
+import { action } from "@storybook/addon-actions";
+import * as React from "react";
+import PostTable, { PostTableRow } from "@@/components/PostTable";
+import Hand, { HandActionType } from "@@/models/Hand";
+import Rank from "@@/models/Rank";
+import Suit from "@@/models/Suit";
+import { PostId, PostTitle, PostBody, PostMinimum } from "@@/models/Post";
+
+export default {
+ title: "PostTable",
+ component: PostTable,
+};
+
+export const example = () => {
+ const posts: PostMinimum[] = [
+ {
+ id: "mvczHP30q8zGEYdlvaMU" as PostId,
+ title:
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore" as
+ PostTitle,
+ body:
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eget egestas purus viverra accumsan in nisl nisi scelerisque eu. Vivamus at augue eget arcu dictum. Lobortis mattis aliquam faucibus purus in massa tempor nec. Purus viverra accumsan in nisl nisi. Adipiscing elit ut aliquam purus. Lorem sed risus ultricies tristique nulla aliquet enim. Purus viverra accumsan in nisl. Volutpat blandit aliquam etiam erat velit scelerisque in dictum. Ornare quam viverra orci sagittis eu volutpat odio facilisis mauris. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Id diam maecenas ultricies mi eget mauris pharetra et. Id leo in vitae turpis. Id cursus metus aliquam eleifend mi in nulla posuere. Fames ac turpis egestas sed tempus urna et pharetra. Mi tempus imperdiet nulla malesuada.\n\nAliquet lectus proin nibh nisl condimentum id venenatis a condimentum. Id donec ultrices tincidunt arcu non sodales. Fusce id velit ut tortor pretium viverra suspendisse. Vel quam elementum pulvinar etiam. Vulputate mi sit amet mauris commodo quis imperdiet massa. Hac habitasse platea dictumst vestibulum rhoncus est. Tellus at urna condimentum mattis pellentesque id. In hendrerit gravida rutrum quisque non. Quis ipsum suspendisse ultrices gravida dictum fusce ut placerat. In tellus integer feugiat scelerisque varius. Sed egestas egestas fringilla phasellus faucibus scelerisque.\n\nViverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis. Nec nam aliquam sem et tortor consequat id. Sed velit dignissim sodales ut. Euismod in pellentesque massa placerat. Pharetra massa massa ultricies mi quis hendrerit dolor. Risus at ultrices mi tempus imperdiet. Duis at tellus at urna condimentum. Tortor at auctor urna nunc id. Cursus risus at ultrices mi tempus imperdiet nulla malesuada. Mauris pellentesque pulvinar pellentesque habitant morbi tristique. Dignissim cras tincidunt lobortis feugiat. Vitae proin sagittis nisl rhoncus mattis rhoncus urna. Id leo in vitae turpis massa sed elementum tempus egestas. Accumsan tortor posuere ac ut consequat semper viverra.\n\nFaucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper. Est ante in nibh mauris. Proin libero nunc consequat interdum varius sit amet mattis vulputate. Ut porttitor leo a diam sollicitudin tempor id eu nisl. Eros donec ac odio tempor orci. Vel elit scelerisque mauris pellentesque pulvinar pellentesque. Lacinia at quis risus sed vulputate. Pellentesque sit amet porttitor eget dolor morbi non arcu. Scelerisque viverra mauris in aliquam sem fringilla. Metus aliquam eleifend mi in nulla posuere sollicitudin aliquam. Vestibulum sed arcu non odio euismod. Leo vel orci porta non pulvinar neque laoreet suspendisse. Convallis a cras semper auctor neque vitae tempus. Scelerisque in dictum non consectetur. Integer quis auctor elit sed vulputate.\n\nPretium aenean pharetra magna ac. Faucibus purus in massa tempor nec feugiat nisl. Elit at imperdiet dui accumsan sit amet. Donec et odio pellentesque diam volutpat. Libero nunc consequat interdum varius. Sodales neque sodales ut etiam sit amet nisl purus in. Auctor eu augue ut lectus arcu bibendum. Sollicitudin ac orci phasellus egestas tellus rutrum. In hac habitasse platea dictumst. Amet venenatis urna cursus eget nunc scelerisque viverra mauris. Feugiat scelerisque varius morbi enim nunc faucibus a pellentesque. Senectus et netus et malesuada fames ac turpis egestas. Placerat duis ultricies lacus sed turpis tincidunt. Sed blandit libero volutpat sed cras. Scelerisque eleifend donec pretium vulputate sapien. Faucibus a pellentesque sit amet porttitor. Ullamcorper a lacus vestibulum sed arcu." as
+ PostBody,
+ hand: new Hand({
+ playerInitialStackSizes: new Map([
+ [0, 38.3],
+ [1, 189.1],
+ [2, 127.9],
+ [3, 74.2],
+ [4, 111],
+ [5, 96.8],
+ ]),
+ playerCards: new Map([
+ [
+ 0,
+ [
+ { rank: Rank.ace, suit: Suit.diamond },
+ { rank: Rank.queen, suit: Suit.club },
+ ],
+ ],
+ [
+ 1,
+ [
+ { rank: Rank.deuce, suit: Suit.diamond },
+ { rank: Rank.five, suit: Suit.heart },
+ ],
+ ],
+ [
+ 3,
+ [
+ { rank: Rank.nine, suit: Suit.club },
+ { rank: Rank.eight, suit: Suit.club },
+ ],
+ ],
+ ]),
+ smallBlindSize: 0.5,
+ antiSize: 0,
+ communityCards: [
+ { rank: Rank.king, suit: Suit.club },
+ { rank: Rank.deuce, suit: Suit.club },
+ { rank: Rank.five, suit: Suit.club },
+ { rank: Rank.queen, suit: Suit.spade },
+ { rank: Rank.ace, suit: Suit.heart },
+ ],
+ preflopActions: [
+ { type: HandActionType.fold, playerIndex: 2, betSize: 0 },
+ { type: HandActionType.raise, playerIndex: 3, betSize: 3 },
+ { type: HandActionType.fold, playerIndex: 4, betSize: 0 },
+ { type: HandActionType.fold, playerIndex: 5, betSize: 0 },
+ { type: HandActionType.call, playerIndex: 0, betSize: 3 },
+ { type: HandActionType.call, playerIndex: 1, betSize: 3 },
+ ],
+ flopActions: [
+ { type: HandActionType.bet, playerIndex: 0, betSize: 1 },
+ { type: HandActionType.call, playerIndex: 1, betSize: 1 },
+ { type: HandActionType.call, playerIndex: 3, betSize: 1 },
+ ],
+ turnActions: [
+ { type: HandActionType.bet, playerIndex: 0, betSize: 1 },
+ { type: HandActionType.call, playerIndex: 1, betSize: 1 },
+ { type: HandActionType.raise, playerIndex: 3, betSize: 4 },
+ { type: HandActionType.call, playerIndex: 0, betSize: 4 },
+ { type: HandActionType.call, playerIndex: 1, betSize: 4 },
+ ],
+ riverActions: [
+ { type: HandActionType.bet, playerIndex: 0, betSize: 30.3 },
+ { type: HandActionType.call, playerIndex: 1, betSize: 30.3 },
+ { type: HandActionType.call, playerIndex: 3, betSize: 30.3 },
+ ],
+ }),
+ heroIndex: 3,
+ likes: 3,
+ dislikes: 2,
+ createdAt: new Date("2020-06-14T01:57:09.917Z"),
+ lastUpdatedAt: new Date("2020-06-14T01:57:09.917Z"),
+ },
+ {
+ id: "00000000000000000000" as PostId,
+ title: "abcdefgh" as PostTitle,
+ body: "abcdefgh" as PostBody,
+ hand: new Hand({
+ playerInitialStackSizes: new Map([
+ [0, 1],
+ [1, 1],
+ ]),
+ playerCards: new Map([
+ [
+ 0,
+ [
+ { rank: Rank.ace, suit: Suit.spade },
+ { rank: Rank.king, suit: Suit.spade },
+ ],
+ ],
+ [
+ 1,
+ [
+ { rank: Rank.ace, suit: Suit.heart },
+ { rank: Rank.king, suit: Suit.heart },
+ ],
+ ],
+ ]),
+ smallBlindSize: 0.5,
+ antiSize: 0,
+ communityCards: [],
+ preflopActions: [
+ { type: HandActionType.fold, playerIndex: 0, betSize: 0.5 },
+ ],
+ flopActions: [],
+ turnActions: [],
+ riverActions: [],
+ }),
+ heroIndex: 1,
+ likes: 0,
+ dislikes: 0,
+ createdAt: new Date(),
+ lastUpdatedAt: new Date(),
+ },
+ {
+ id: "zzzzzzzzzzzzzzzzzzzz" as PostId,
+ title:
+ "In egestas erat imperdiet sed. In massa tempor nec feugiat nisl pretium. Urna condimentum mattis pellentesque id nibh. Massa sapien faucibus et molestie ac feugiat sed lectus. Facilisis gravida neque convallis a cras semper auctor neque vitae. Aliquam faucibus purus in massa tempor nec feugiat. Sit amet purus gravida quis blandit. Ligula ullamcorper malesuada proin libero nunc consequat. Eleifend mi in nulla posuere sollicitudin aliquam ultrices sagittis orci. Enim nulla aliquet porttitor lacus luctus accumsan tortor. Facilisi etiam dignissim diam quis enim. Sagittis aliquam malesuada bibendum arcu. Tristique senectus et netus et malesuada fames ac. Non tellus orci ac auctor augue. Massa vitae tortor condimentum lacinia quis vel eros donec. Arcu non sodales neque sodales ut etiam sit amet nisl. Rhoncus dolor purus non enim praesent elementum. Pulvinar etiam non quam lacus suspendisse faucibus interdum posuere lorem. Neque aliquam vestibulum morbi blandit cursus risus at. Mauris cursus mattis molestie a iaculis at. Facilisis sed odio morbi quis commodo. Tincidunt tortor aliquam nulla facilisi cras fermentum odio. Lorem ipsum dolor sit amet consectetur adipiscing. Bibendum est ultricies integer quis auctor. Ipsum consequat nisl vel pretium. Accumsan lacus vel facilisis volutpat est. Amet dictum sit amet justo. Condimentum lacinia quis vel eros donec ac. Convallis tellus id interdum velit laoreet. Nunc lobortis mattis aliquam faucibus purus. Ut sem nulla pharetra diam sit. Mauris pellentesque pulvinar pellentesque habitant morbi. Erat velit scelerisque in dictum non. Enim tortor at auctor urna nunc id cursus. Orci ac auctor augue mauris augue neque gravida in. Ultrices sagittis orci a scelerisque purus semper eget duis. Erat pellentesque adipiscing commodo elit at imperdiet. Feugiat nisl pretium fusce id. Praesent elementum facilisis leo vel fringilla est ullamcorper eget nulla. Dictum non consectetur a erat nam at lectus urna. Quisque non tellus orci ac auctor. Mus mauris vitae ultricies leo integer. Pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies. Elementum nisi quis eleifend quam adipiscing vitae. Aenean euismod elementum nisi quis eleifend quam adipiscing. Sapien faucibus et molestie ac feugiat sed lectus vestibulum. Mus mauris vitae ultricies leo integer malesuada nunc vel. Nisi quis eleifend quam adipiscing. Consequat nisl vel pretium lectus quam. Arcu dui vivamus arcu felis bibendum. Nisl pretium fusce id velit. Lobortis scelerisque fermentum dui faucibus in ornare quam viverra. Non enim praesent elementum facilisis. Tortor id aliquet lectus proin nibh nisl. Pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus. Nibh sit amet commodo nulla facilisi. Nunc mattis enim ut tellus. Suspendisse in est ante in nibh mauris cursus. Pellentesque nec nam aliquam sem et tortor consequat id. Mi bibendum neque egestas congue quisque egestas. Sed id semper risus in hendrerit gravida rutrum. Amet luctus venenatis lectus magna fringilla. Neque volutpat ac tincidunt vitae semper quis lectus nulla at. Et malesuada fames ac turpis egestas integer eget aliquet. Nulla facilisi etiam dignissim diam quis enim lobortis scelerisque fermentum. Sed cras ornare arcu dui vivamus arcu felis bibendum ut. Turpis massa tincidunt dui ut ornare. Ipsum nunc aliquet bibendum enim facilisis gravida neque convallis. Ac tortor vitae purus faucibus ornare suspendisse. Diam in arcu cursus euismod quis viverra nibh cras pulvinar. Dui sapien eget mi proin sed. Ullamcorper sit amet risus nullam eget. Nam aliquam sem et tortor consequat id porta. At quis risus sed vulputate odio ut enim blandit. Gravida rutrum quisque non tellus orci ac. Congue quisque egestas diam in arcu. Venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam. Enim sed faucibus turpis in eu. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Molestie a iaculis at erat pellentesque adipiscing. Dolor sit amet consectetur adipiscing. Non arcu risus quis varius quam quisque id diam vel. Bibendum arcu vitae elementum curabitur vitae nunc sed velit dignissim. Phasellus faucibus scelerisque eleifend donec pretium vulputate sapien nec. Ut eu sem integer vitae justo eget magna fermentum iaculis. Vitae et leo duis ut diam quam nulla porttitor. Risus viverra adipiscing at in tellus integer feugiat. Arcu cursus vitae congue mauris rhoncus aenean vel elit scelerisque. Maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum. Est pellentesque elit ullamcorper dignissim cras tincidunt. Id nibh tortor id aliquet. Nec feugiat nisl pretium fusce id velit ut. Duis tristique sollicitudin nibh sit amet. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor. Amet facilisis magna etiam tempor orci. Quis commodo odio aenean sed adipiscing. Tempus egestas sed sed risus pretium. Sollicitudin tempor id eu nisl nunc mi. Sapien et ligula ullamcorper malesuada proin libero. Pellentesque pulvinar pellentesque habitant morbi tristique senectus." as
+ PostTitle,
+ body:
+ "Sapien et ligula ullamcorper malesuada proin. In mollis nunc sed id semper risus. Enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac. Egestas erat imperdiet sed euismod. Pretium vulputate sapien nec sagittis aliquam malesuada bibendum. Magna sit amet purus gravida quis blandit turpis cursus in. Elit ut aliquam purus sit amet luctus. Lectus nulla at volutpat diam ut venenatis tellus in metus. Enim diam vulputate ut pharetra sit amet aliquam id. Quam nulla porttitor massa id. A pellentesque sit amet porttitor eget. Convallis convallis tellus id interdum velit. Nulla posuere sollicitudin aliquam ultrices sagittis orci a scelerisque purus. Pretium lectus quam id leo in. Enim eu turpis egestas pretium aenean pharetra magna ac placerat. Sollicitudin aliquam ultrices sagittis orci a. Tellus integer feugiat scelerisque varius morbi enim nunc. Quam quisque id diam vel quam. Cras ornare arcu dui vivamus arcu felis. Leo in vitae turpis massa sed elementum tempus egestas. Neque viverra justo nec ultrices dui sapien eget mi. Mollis aliquam ut porttitor leo a diam sollicitudin tempor id. Mattis nunc sed blandit libero volutpat sed cras ornare. Dignissim sodales ut eu sem. Viverra justo nec ultrices dui sapien. Pharetra pharetra massa massa ultricies mi quis hendrerit. Nibh cras pulvinar mattis nunc. In cursus turpis massa tincidunt. Cras pulvinar mattis nunc sed blandit libero volutpat sed cras. In ante metus dictum at tempor commodo ullamcorper a lacus. Tristique sollicitudin nibh sit amet commodo nulla. Pharetra et ultrices neque ornare aenean euismod elementum nisi. Dictum at tempor commodo ullamcorper a lacus vestibulum. Auctor neque vitae tempus quam. Vitae suscipit tellus mauris a. Velit egestas dui id ornare. Mi in nulla posuere sollicitudin aliquam. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem sed risus ultricies tristique. Maecenas pharetra convallis posuere morbi. Mi tempus imperdiet nulla malesuada pellentesque elit eget gravida. Morbi tristique senectus et netus et malesuada fames ac turpis. At erat pellentesque adipiscing commodo. Tellus at urna condimentum mattis. Interdum velit euismod in pellentesque massa placerat duis ultricies. Commodo viverra maecenas accumsan lacus vel facilisis volutpat. Commodo odio aenean sed adipiscing diam donec adipiscing tristique. Nulla aliquet enim tortor at auctor urna nunc. Ultricies tristique nulla aliquet enim tortor at. Sed sed risus pretium quam. Eu consequat ac felis donec et odio pellentesque diam. Id semper risus in hendrerit gravida. Elementum sagittis vitae et leo duis ut diam quam. Praesent elementum facilisis leo vel fringilla. Sagittis purus sit amet volutpat consequat mauris nunc congue. Sed elementum tempus egestas sed sed risus. Orci eu lobortis elementum nibh tellus. Maecenas pharetra convallis posuere morbi leo urna molestie at. Pellentesque elit ullamcorper dignissim cras tincidunt. Congue quisque egestas diam in arcu cursus euismod. Orci phasellus egestas tellus rutrum tellus. Elementum facilisis leo vel fringilla est ullamcorper eget nulla. Scelerisque varius morbi enim nunc. Viverra aliquet eget sit amet. Sagittis vitae et leo duis ut diam quam nulla porttitor. Diam ut venenatis tellus in metus vulputate. In fermentum et sollicitudin ac orci phasellus egestas. Ac turpis egestas sed tempus urna. Senectus et netus et malesuada fames ac turpis egestas. At elementum eu facilisis sed odio morbi quis commodo. Donec ultrices tincidunt arcu non sodales neque sodales. Luctus accumsan tortor posuere ac. Purus non enim praesent elementum facilisis leo vel fringilla est. Lectus nulla at volutpat diam ut. Vestibulum sed arcu non odio euismod lacinia. Elit duis tristique sollicitudin nibh sit amet commodo. Odio ut sem nulla pharetra diam sit amet nisl suscipit. Tempus iaculis urna id volutpat lacus laoreet. Magna fermentum iaculis eu non diam phasellus vestibulum. Sagittis eu volutpat odio facilisis mauris sit amet massa. Dignissim cras tincidunt lobortis feugiat vivamus at augue eget. Varius vel pharetra vel turpis nunc eget lorem dolor sed. Purus sit amet volutpat consequat mauris nunc congue. Odio ut sem nulla pharetra. Interdum velit euismod in pellentesque massa placerat duis ultricies. Ipsum suspendisse ultrices gravida dictum fusce. Est ultricies integer quis auctor elit sed vulputate mi sit. Netus et malesuada fames ac turpis egestas integer eget. Volutpat consequat mauris nunc congue nisi vitae suscipit. Felis imperdiet proin fermentum leo vel orci porta non. Risus nec feugiat in fermentum posuere urna. Odio morbi quis commodo odio aenean sed adipiscing. Sed ullamcorper morbi tincidunt ornare massa eget egestas purus. Morbi tristique senectus et netus et malesuada fames ac. Vivamus arcu felis bibendum ut tristique et egestas quis. Imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada. Aliquet nec ullamcorper sit amet risus nullam eget felis. Eget nunc scelerisque viverra mauris in aliquam sem fringilla ut. Malesuada pellentesque elit eget gravida cum sociis natoque penatibus et. Nunc congue nisi vitae suscipit." as
+ PostBody,
+ hand: new Hand({
+ playerInitialStackSizes: new Map([
+ [0, 100000000],
+ [1, 100000000],
+ [2, 100000000],
+ [3, 100000000],
+ [4, 100000000],
+ [5, 100000000],
+ [6, 100000000],
+ [7, 100000000],
+ [8, 100000000],
+ [9, 100000000],
+ ]),
+ playerCards: new Map([
+ [
+ 0,
+ [
+ { rank: Rank.ace, suit: Suit.spade },
+ { rank: Rank.ace, suit: Suit.heart },
+ ],
+ ],
+ [
+ 1,
+ [
+ { rank: Rank.king, suit: Suit.diamond },
+ { rank: Rank.king, suit: Suit.club },
+ ],
+ ],
+ [
+ 2,
+ [
+ { rank: Rank.queen, suit: Suit.heart },
+ { rank: Rank.queen, suit: Suit.club },
+ ],
+ ],
+ [
+ 3,
+ [
+ { rank: Rank.jack, suit: Suit.spade },
+ { rank: Rank.jack, suit: Suit.diamond },
+ ],
+ ],
+ [
+ 4,
+ [
+ { rank: Rank.ten, suit: Suit.heart },
+ { rank: Rank.ten, suit: Suit.club },
+ ],
+ ],
+ [
+ 5,
+ [
+ { rank: Rank.ace, suit: Suit.diamond },
+ { rank: Rank.king, suit: Suit.spade },
+ ],
+ ],
+ [
+ 6,
+ [
+ { rank: Rank.king, suit: Suit.heart },
+ { rank: Rank.queen, suit: Suit.spade },
+ ],
+ ],
+ [
+ 7,
+ [
+ { rank: Rank.queen, suit: Suit.diamond },
+ { rank: Rank.jack, suit: Suit.heart },
+ ],
+ ],
+ [
+ 8,
+ [
+ { rank: Rank.jack, suit: Suit.club },
+ { rank: Rank.ten, suit: Suit.spade },
+ ],
+ ],
+ [
+ 9,
+ [
+ { rank: Rank.deuce, suit: Suit.spade },
+ { rank: Rank.deuce, suit: Suit.heart },
+ ],
+ ],
+ ]),
+ smallBlindSize: 0.5,
+ antiSize: 0,
+ communityCards: [
+ { rank: Rank.nine, suit: Suit.heart },
+ { rank: Rank.nine, suit: Suit.diamond },
+ { rank: Rank.nine, suit: Suit.club },
+ { rank: Rank.eight, suit: Suit.club },
+ { rank: Rank.ace, suit: Suit.club },
+ ],
+ preflopActions: [
+ { type: HandActionType.raise, playerIndex: 2, betSize: 3 },
+ { type: HandActionType.raise, playerIndex: 3, betSize: 9 },
+ { type: HandActionType.call, playerIndex: 4, betSize: 9 },
+ { type: HandActionType.fold, playerIndex: 5, betSize: 0 },
+ { type: HandActionType.fold, playerIndex: 6, betSize: 0 },
+ { type: HandActionType.fold, playerIndex: 7, betSize: 0 },
+ { type: HandActionType.fold, playerIndex: 8, betSize: 0 },
+ { type: HandActionType.call, playerIndex: 9, betSize: 9 },
+ { type: HandActionType.raise, playerIndex: 0, betSize: 24 },
+ { type: HandActionType.call, playerIndex: 1, betSize: 24 },
+ { type: HandActionType.call, playerIndex: 2, betSize: 24 },
+ { type: HandActionType.call, playerIndex: 3, betSize: 24 },
+ { type: HandActionType.call, playerIndex: 4, betSize: 24 },
+ ],
+ flopActions: [
+ { type: HandActionType.bet, playerIndex: 0, betSize: 50 },
+ { type: HandActionType.call, playerIndex: 1, betSize: 50 },
+ { type: HandActionType.raise, playerIndex: 2, betSize: 100 },
+ { type: HandActionType.call, playerIndex: 3, betSize: 100 },
+ { type: HandActionType.call, playerIndex: 4, betSize: 100 },
+ { type: HandActionType.call, playerIndex: 0, betSize: 100 },
+ { type: HandActionType.call, playerIndex: 1, betSize: 100 },
+ ],
+ turnActions: [
+ { type: HandActionType.check, playerIndex: 0, betSize: 0 },
+ { type: HandActionType.bet, playerIndex: 1, betSize: 320 },
+ { type: HandActionType.call, playerIndex: 2, betSize: 320 },
+ { type: HandActionType.call, playerIndex: 3, betSize: 320 },
+ { type: HandActionType.call, playerIndex: 4, betSize: 320 },
+ { type: HandActionType.raise, playerIndex: 0, betSize: 750 },
+ { type: HandActionType.raise, playerIndex: 1, betSize: 1800 },
+ { type: HandActionType.fold, playerIndex: 2, betSize: 320 },
+ { type: HandActionType.fold, playerIndex: 3, betSize: 320 },
+ { type: HandActionType.fold, playerIndex: 4, betSize: 320 },
+ { type: HandActionType.call, playerIndex: 0, betSize: 1800 },
+ ],
+ riverActions: [
+ { type: HandActionType.check, playerIndex: 0, betSize: 0 },
+ { type: HandActionType.check, playerIndex: 1, betSize: 0 },
+ ],
+ }),
+ heroIndex: 0,
+ likes: 2 ** 29,
+ dislikes: 2 ** 12,
+ createdAt: new Date(1292603960743),
+ lastUpdatedAt: new Date(1392603960743),
+ },
+ {
+ id: "rgaergba" as PostId,
+ title:
+ "suspendisse interdum consectetur libero id undisse interdum consectetur libero deid consectetur libero deid" as
+ PostTitle,
+ body:
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." as
+ PostBody,
+ likes: 125,
+ dislikes: 12,
+ hand: new Hand({
+ playerInitialStackSizes: new Map(
+ [82, 103.2, 107.6, 113.2, 100.6, 94.8].map((v, k) => [k, v])
+ ),
+ playerCards: new Map([
+ [
+ 2,
+ [
+ { rank: Rank.ace, suit: Suit.diamond },
+ { rank: Rank.king, suit: Suit.heart },
+ ],
+ ],
+ [
+ 3,
+ [
+ { rank: Rank.four, suit: Suit.spade },
+ { rank: Rank.four, suit: Suit.heart },
+ ],
+ ],
+ ]),
+ smallBlindSize: 0.4,
+ antiSize: 0,
+ communityCards: [
+ { rank: Rank.four, suit: Suit.club },
+ { rank: Rank.seven, suit: Suit.club },
+ { rank: Rank.six, suit: Suit.spade },
+ { rank: Rank.three, suit: Suit.spade },
+ ],
+ preflopActions: [
+ { type: HandActionType.raise, playerIndex: 2, betSize: 3 },
+ { type: HandActionType.call, playerIndex: 3, betSize: 3 },
+ { type: HandActionType.fold, playerIndex: 4, betSize: 0 },
+ { type: HandActionType.fold, playerIndex: 5, betSize: 0 },
+ { type: HandActionType.call, playerIndex: 0, betSize: 3 },
+ { type: HandActionType.fold, playerIndex: 1, betSize: 1 },
+ ],
+ flopActions: [
+ { type: HandActionType.check, playerIndex: 0, betSize: 0 },
+ { type: HandActionType.bet, playerIndex: 2, betSize: 4.8 },
+ { type: HandActionType.call, playerIndex: 3, betSize: 4.8 },
+ { type: HandActionType.fold, playerIndex: 0, betSize: 0 },
+ ],
+ turnActions: [
+ { type: HandActionType.bet, playerIndex: 2, betSize: 9.4 },
+ { type: HandActionType.raise, playerIndex: 3, betSize: 22 },
+ { type: HandActionType.fold, playerIndex: 2, betSize: 9.4 },
+ ],
+ riverActions: [],
+ }),
+ heroIndex: 2,
+ createdAt: new Date(),
+ lastUpdatedAt: new Date(),
+ },
+ ];
+
+ return (
+
+ {posts.map((post) => (
+
+ ))}
+
+ );
+};
diff --git a/components/PostTable/PostTable.tsx b/components/PostTable/PostTable.tsx
new file mode 100644
index 0000000..78fbb13
--- /dev/null
+++ b/components/PostTable/PostTable.tsx
@@ -0,0 +1,119 @@
+import * as React from "react";
+import styled from "styled-components";
+import { MOBILE_MEDIA } from "@@/constants/mediaquery";
+
+interface Props extends React.Attributes {
+ className?: string;
+ style?: React.CSSProperties;
+ children?: React.ReactElement[];
+}
+
+/**
+ * Write a description here.
+ */
+export default function PostTable({ children, ...props }: Props) {
+ return (
+
+
+
+
+ Title
+
+ Likes
+
+ Board
+
+ Position
+
+ Final Pot
+
+ Created
+
+
+ {children}
+
+ );
+}
+
+const Root = styled.div`
+ --grid-template-columns: 100px minmax(256px, 1fr) 80px 116px 60px 80px 120px;
+ --grid-template-areas: "hero-cards title likes community-cards hero-position final-pot-size creation-date";
+ --column-gap: 24px;
+ --header-font-size: 14px;
+ --cell-font-size: 16px;
+ width: 100%;
+ padding: 8px 0;
+ border-radius: 4px;
+ box-shadow: 0px 0px 12px #222f3e1f, 0px 12px 24px #222f3e0f;
+ overflow-x: scroll;
+ user-select: none;
+
+ ${MOBILE_MEDIA} {
+ --grid-template-columns: 80px minmax(128px, 1fr) 72px 100px 52px 64px 100px;
+ --column-gap: 16px;
+ --header-font-size: 12px;
+ --cell-font-size: 14px;
+ }
+`;
+
+const HeadRow = styled.div`
+ display: grid;
+ grid-template-columns: var(--grid-template-columns);
+ grid-template-areas: var(--grid-template-areas);
+ align-items: center;
+ column-gap: var(--column-gap);
+ padding: 8px var(--column-gap);
+ text-decoration: none;
+`;
+
+const HeroCardsHeadCell = styled.div`
+ grid-area: hero-cards;
+`;
+
+const TitleHeadCell = styled.div`
+ grid-area: title;
+ color: #576574;
+ font-size: var(--header-font-size);
+ font-weight: bold;
+ text-transform: uppercase;
+`;
+
+const LikesHeadCell = styled.div`
+ grid-area: likes;
+ color: #576574;
+ font-size: var(--header-font-size);
+ font-weight: bold;
+ text-transform: uppercase;
+`;
+
+const CommunityCardsHeadCell = styled.div`
+ grid-area: community-cards;
+ color: #576574;
+ font-size: var(--header-font-size);
+ font-weight: bold;
+ text-transform: uppercase;
+`;
+
+const HeroPositionHeadCell = styled.div`
+ grid-area: hero-position;
+ color: #576574;
+ font-size: var(--header-font-size);
+ font-weight: bold;
+ text-transform: uppercase;
+`;
+
+const FinalPotSizeHeadCell = styled.div`
+ grid-area: final-pot-size;
+ color: #576574;
+ font-size: var(--header-font-size);
+ font-weight: bold;
+ text-transform: uppercase;
+`;
+
+const CreationDateHeadCell = styled.div`
+ grid-area: creation-date;
+ color: #576574;
+ font-size: var(--header-font-size);
+ font-weight: bold;
+ text-transform: uppercase;
+`;
diff --git a/components/PostTable/PostTableRow.tsx b/components/PostTable/PostTableRow.tsx
new file mode 100644
index 0000000..2d9ba01
--- /dev/null
+++ b/components/PostTable/PostTableRow.tsx
@@ -0,0 +1,174 @@
+import { formatDistanceStrict } from "date-fns";
+import Link from "next/link";
+import numeral from "numeral";
+import * as React from "react";
+import styled from "styled-components";
+import { ThumbsUpIcon } from "@@/components/Icon";
+import LandscapePlayingCard from "@@/components/LandscapePlayingCard";
+import PortraitPlayingCard from "@@/components/PortraitPlayingCard";
+import { PostMinimum } from "@@/models/Post";
+import getPositionByPlayerAndIndex from "@@/utilities/getPositionByPlayerAndIndex";
+
+interface Props extends React.Attributes {
+ post: PostMinimum;
+ onClick?: React.MouseEventHandler;
+ className?: string;
+ style?: React.CSSProperties;
+}
+
+/**
+ * Write a description here.
+ */
+export default function PostTableRow({
+ post,
+ onClick = () => {},
+ ...props
+}: Props) {
+ return (
+
+ {
+ onClick(e);
+
+ e.currentTarget.blur();
+ }}
+ {...props}
+ >
+
+
+
+
+
+ {post.title}
+
+
+
+
+
+ {post.likes >= 1000
+ ? numeral(post.likes).format("0.0a")
+ : post.likes}
+
+
+
+
+ {Array.from({ length: 5 }, (_, i) => (
+
+ ))}
+
+
+
+ {getPositionByPlayerAndIndex(post.hand.playerLength, post.heroIndex)}
+
+
+
+ {numeral(post.hand.finalPotSize).format("0.0a")} BB
+
+
+
+ {formatDistanceStrict(post.createdAt, new Date())} ago
+
+
+
+ );
+}
+
+const Root = styled.a`
+ display: inline-grid;
+ min-width: 100%;
+ grid-template-columns: var(--grid-template-columns);
+ grid-template-areas: var(--grid-template-areas);
+ align-items: center;
+ column-gap: var(--column-gap);
+ padding: 8px var(--column-gap);
+ text-decoration: none;
+ cursor: pointer;
+
+ &:hover {
+ background-color: #f7f7f7;
+ }
+
+ &:focus {
+ outline: none;
+ background-color: #f7f7f7;
+ }
+`;
+
+const HeroCards = styled.div`
+ grid-area: hero-cards;
+ display: flex;
+
+ & > *:nth-of-type(n + 2) {
+ margin-left: calc(var(--column-gap) / 3);
+ }
+`;
+
+const Title = styled.div`
+ grid-area: title;
+ color: #0f151c;
+ font-size: calc(var(--cell-font-size) * 1.125);
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow-x: hidden;
+`;
+
+const Likes = styled.div`
+ grid-area: likes;
+ display: flex;
+ align-items: center;
+ color: #576574;
+ font-size: var(--cell-font-size);
+`;
+
+const LikeIcon = styled(ThumbsUpIcon)`
+ width: calc(var(--cell-font-size) * 1.25);
+ height: calc(var(--cell-font-size) * 1.25);
+`;
+
+const LikeCount = styled.span`
+ display: inline-block;
+ margin-left: 4px;
+ color: #576574;
+ font-size: var(--cell-font-size);
+`;
+
+const CommunityCards = styled.div`
+ grid-area: community-cards;
+ display: flex;
+ justify-content: flex-start;
+
+ & > * {
+ &:nth-of-type(n + 2) {
+ margin-left: calc(var(--column-gap) / 6);
+ }
+ }
+`;
+
+const HeroPosition = styled.div`
+ grid-area: hero-position;
+ color: #576574;
+ font-size: var(--cell-font-size);
+`;
+
+const FinalPotSize = styled.div`
+ grid-area: final-pot-size;
+ color: #576574;
+ font-size: var(--cell-font-size);
+`;
+
+const CreationDate = styled.div`
+ grid-area: creation-date;
+ color: #576574;
+ font-size: var(--cell-font-size);
+`;
diff --git a/components/PostTable/index.ts b/components/PostTable/index.ts
new file mode 100644
index 0000000..e7135c4
--- /dev/null
+++ b/components/PostTable/index.ts
@@ -0,0 +1,2 @@
+export { default } from "./PostTable";
+export { default as PostTableRow } from "./PostTableRow";
diff --git a/components/TextArea/TextArea.tsx b/components/TextArea/TextArea.tsx
index 102b891..fbf7b9e 100644
--- a/components/TextArea/TextArea.tsx
+++ b/components/TextArea/TextArea.tsx
@@ -76,6 +76,7 @@ const Root = styled.textarea<{
::placeholder {
color: #c8d6e5;
font-size: 16px;
+ user-select: none;
}
:hover,
diff --git a/hooks/usePost.ts b/hooks/usePost.ts
index 6efbef4..806fc29 100644
--- a/hooks/usePost.ts
+++ b/hooks/usePost.ts
@@ -38,7 +38,7 @@ export default function usePost({ postId }: { postId: PostId }) {
isInitialized: true,
}));
});
- }, [postId, post, apolloClient, authenticationToken]);
+ }, [postId, post, apolloClient, authenticationToken, isLoading]);
const updateLocally = React.useCallback(
(updater: (post: Post | null) => Post | null) =>
diff --git a/package-lock.json b/package-lock.json
index d2b7f5b..1e55803 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3028,7 +3028,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -3049,12 +3050,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -3069,17 +3072,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -3196,7 +3202,8 @@
"inherits": {
"version": "2.0.4",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -3208,6 +3215,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -3222,6 +3230,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -3229,12 +3238,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -3253,6 +3264,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -3342,7 +3354,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -3354,6 +3367,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -3439,7 +3453,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -3475,6 +3490,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -3494,6 +3510,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -3537,12 +3554,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -5391,6 +5410,11 @@
"integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==",
"dev": true
},
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@@ -5763,7 +5787,6 @@
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
- "dev": true,
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
@@ -7300,6 +7323,16 @@
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001031.tgz",
"integrity": "sha512-DpAP5a1NGRLgYfaNCaXIRyGARi+3tJA2quZXNNA1Du26VyVkqvy2tznNu5ANyN1Y5aX44QDotZSVSUSi2uMGjg=="
},
+ "canvas": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.6.1.tgz",
+ "integrity": "sha512-S98rKsPcuhfTcYbtF53UIJhcbgIAK533d1kJKMwsMwAIFgfd58MOyxRud3kktlzWiEkFliaJtvyZCBtud/XVEA==",
+ "requires": {
+ "nan": "^2.14.0",
+ "node-pre-gyp": "^0.11.0",
+ "simple-get": "^3.0.3"
+ }
+ },
"capture-exit": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
@@ -7700,8 +7733,7 @@
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"collapse-white-space": {
"version": "1.0.6",
@@ -7828,8 +7860,7 @@
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
- "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
- "dev": true
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"constantinople": {
"version": "3.1.2",
@@ -8366,6 +8397,14 @@
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
},
+ "decompress-response": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+ "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+ "requires": {
+ "mimic-response": "^2.0.0"
+ }
+ },
"deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
@@ -8380,6 +8419,11 @@
"regexp.prototype.flags": "^1.2.0"
}
},
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+ },
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -8453,8 +8497,7 @@
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
- "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
- "dev": true
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
"depd": {
"version": "1.1.2",
@@ -8486,6 +8529,11 @@
"repeat-string": "^1.5.4"
}
},
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
+ },
"detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -9838,7 +9886,6 @@
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
- "dev": true,
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
@@ -9854,7 +9901,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -9863,7 +9909,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -9874,7 +9919,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -10628,8 +10672,7 @@
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
- "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
- "dev": true
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
"has-value": {
"version": "1.0.0",
@@ -11040,6 +11083,14 @@
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
"dev": true
},
+ "ignore-walk": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
+ "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
"immer": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz",
@@ -11136,8 +11187,7 @@
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
- "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
- "dev": true
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"inline-style-parser": {
"version": "0.1.1",
@@ -14005,6 +14055,11 @@
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"dev": true
},
+ "mimic-response": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
+ },
"min-document": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
@@ -14105,6 +14160,25 @@
"minipass": "^3.0.0"
}
},
+ "minizlib": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
+ "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
+ "requires": {
+ "minipass": "^2.9.0"
+ },
+ "dependencies": {
+ "minipass": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
+ "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ }
+ }
+ },
"mississippi": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
@@ -14235,6 +14309,26 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
+ "needle": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz",
+ "integrity": "sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==",
+ "requires": {
+ "debug": "^3.2.6",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
@@ -15328,6 +15422,23 @@
}
}
},
+ "node-pre-gyp": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
+ "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==",
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.1",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.2.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4"
+ }
+ },
"node-releases": {
"version": "1.1.50",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.50.tgz",
@@ -15343,6 +15454,15 @@
}
}
},
+ "nopt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
+ "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
"normalize-html-whitespace": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/normalize-html-whitespace/-/normalize-html-whitespace-1.0.0.tgz",
@@ -15382,6 +15502,29 @@
"sort-keys": "^1.0.0"
}
},
+ "npm-bundled": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
+ "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
+ "requires": {
+ "npm-normalize-package-bin": "^1.0.1"
+ }
+ },
+ "npm-normalize-package-bin": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
+ "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
+ },
+ "npm-packlist": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
+ "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1",
+ "npm-normalize-package-bin": "^1.0.1"
+ }
+ },
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -15395,7 +15538,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
- "dev": true,
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
@@ -15420,8 +15562,7 @@
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"numeral": {
"version": "2.0.6",
@@ -15642,6 +15783,11 @@
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
"integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
},
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+ },
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
@@ -15653,8 +15799,16 @@
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
- "dev": true
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
},
"p-each-series": {
"version": "2.1.0",
@@ -16993,6 +17147,17 @@
"schema-utils": "^2.0.1"
}
},
+ "rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ }
+ },
"react": {
"version": "16.13.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.13.0.tgz",
@@ -17262,7 +17427,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -17283,12 +17449,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -17303,17 +17471,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -17430,7 +17601,8 @@
"inherits": {
"version": "2.0.4",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -17442,6 +17614,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -17456,6 +17629,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -17463,12 +17637,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -17487,6 +17663,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -17576,7 +17753,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -17588,6 +17766,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -17673,7 +17852,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -17709,6 +17889,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -17728,6 +17909,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -17771,12 +17953,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -19361,8 +19545,7 @@
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
- "dev": true
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"set-value": {
"version": "2.0.1",
@@ -19483,8 +19666,22 @@
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
- "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
- "dev": true
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
+ "simple-concat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
+ "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
+ },
+ "simple-get": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
+ "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
+ "requires": {
+ "decompress-response": "^4.2.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
},
"simple-swizzle": {
"version": "0.2.2",
@@ -20074,6 +20271,11 @@
"min-indent": "^1.0.0"
}
},
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+ },
"style-loader": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.0.0.tgz",
@@ -20293,6 +20495,39 @@
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="
},
+ "tar": {
+ "version": "4.4.13",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
+ "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.8.6",
+ "minizlib": "^1.2.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.3"
+ },
+ "dependencies": {
+ "fs-minipass": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
+ "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
+ "requires": {
+ "minipass": "^2.6.0"
+ }
+ },
+ "minipass": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
+ "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ }
+ }
+ },
"telejson": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/telejson/-/telejson-3.3.0.tgz",
@@ -21672,7 +21907,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -21693,12 +21929,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -21713,17 +21951,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -21840,7 +22081,8 @@
"inherits": {
"version": "2.0.4",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -21852,6 +22094,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -21866,6 +22109,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -21873,12 +22117,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -21897,6 +22143,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -21986,7 +22233,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -21998,6 +22246,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -22083,7 +22332,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -22119,6 +22369,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -22138,6 +22389,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -22181,12 +22433,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -22429,7 +22683,6 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
- "dev": true,
"requires": {
"string-width": "^1.0.2 || 2"
},
@@ -22437,20 +22690,17 @@
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
@@ -22460,7 +22710,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
"requires": {
"ansi-regex": "^3.0.0"
}
diff --git a/package.json b/package.json
index c084ff7..fe59ead 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"@bugsnag/js": "^7.1.1",
"@tippyjs/react": "^4.0.0-alpha.3",
"apollo-boost": "^0.4.8",
+ "canvas": "^2.6.1",
"date-fns": "^2.11.1",
"firebase": "^7.10.0",
"graphql": "^15.0.0",
diff --git a/pageComponents/NotFoundPage/NotFoundPage.module.css b/pageComponents/NotFoundPage/NotFoundPage.module.css
new file mode 100644
index 0000000..68590ae
--- /dev/null
+++ b/pageComponents/NotFoundPage/NotFoundPage.module.css
@@ -0,0 +1,8 @@
+.root {
+ min-width: 375px;
+}
+
+.illustration {
+ width: 50%;
+ margin: 0 auto;
+}
\ No newline at end of file
diff --git a/pageComponents/NotFoundPage/NotFoundPage.tsx b/pageComponents/NotFoundPage/NotFoundPage.tsx
new file mode 100644
index 0000000..5cda7c1
--- /dev/null
+++ b/pageComponents/NotFoundPage/NotFoundPage.tsx
@@ -0,0 +1,31 @@
+import * as React from "react";
+import styled from "styled-components";
+import HeadBar from "@@/components/HeadBar";
+import FootBar from "@@/components/FootBar";
+import { Void } from "@@/components/Illustration";
+import classes from "./NotFoundPage.module.css";
+
+interface Props extends React.Attributes {
+ className?: string;
+ style?: React.CSSProperties;
+ children?: React.ReactNode;
+}
+
+/**
+ * Write a description here.
+ */
+export default function NotFoundPage({ ...props }: Props) {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+}
+
+const Root = styled.div``;
diff --git a/pageComponents/NotFoundPage/index.ts b/pageComponents/NotFoundPage/index.ts
new file mode 100644
index 0000000..225a377
--- /dev/null
+++ b/pageComponents/NotFoundPage/index.ts
@@ -0,0 +1 @@
+export { default } from "./NotFoundPage";
diff --git a/pageComponents/PostDetailPage/NewAnswerForm.tsx b/pageComponents/PostDetailPage/NewAnswerForm.tsx
new file mode 100644
index 0000000..da7e217
--- /dev/null
+++ b/pageComponents/PostDetailPage/NewAnswerForm.tsx
@@ -0,0 +1,59 @@
+import * as React from "react";
+import MultilineTextSubmissionForm from "@@/components/MultilineTextSubmissionForm";
+import useMyself from "@@/hooks/useMyself";
+import { PostId } from "@@/models/Post";
+import useAnswerCreation, {
+ AnswerBodyValidationErrorType,
+} from "@@/hooks/useAnswerCreation";
+
+interface Props extends React.Attributes {
+ postId: PostId;
+ className?: string;
+ style?: React.CSSProperties;
+}
+
+/**
+ * Write a description here.
+ */
+export default function NewAnswerForm({ postId, ...props }: Props) {
+ const { myself, isLoading: isMyselfLoading } = useMyself();
+ const {
+ body,
+ isValid,
+ bodyValidationErrorTypes,
+ isSubmitting,
+ setBody,
+ submit,
+ } = useAnswerCreation({ postId });
+
+ if (isMyselfLoading || !myself) {
+ return null;
+ }
+
+ return (
+ setBody(body)}
+ onSubmit={() => submit()}
+ {...props}
+ />
+ );
+}
+
+const BODY_VALIDATION_ERROR_MESSAGE = new Map([
+ [AnswerBodyValidationErrorType.tooShort, "Too short to post."],
+ [
+ AnswerBodyValidationErrorType.tooLong,
+ "Your wonderful comment is too much long! Can you shave it down little bit?",
+ ],
+]);
diff --git a/pageComponents/PostDetailPage/PostDetailPage.tsx b/pageComponents/PostDetailPage/PostDetailPage.tsx
index ca358a2..78214f1 100644
--- a/pageComponents/PostDetailPage/PostDetailPage.tsx
+++ b/pageComponents/PostDetailPage/PostDetailPage.tsx
@@ -9,6 +9,7 @@ import HandPlayerSection from "./HandPlayerSection";
import AnswerList from "./AnswerList";
import PostBody from "./PostBody";
import PostTitle from "./PostTitle";
+import NewAnswerForm from "./NewAnswerForm";
interface Props extends React.Attributes {
postId: PostId;
@@ -55,6 +56,12 @@ export default function PostDetailPage({
<_PostBody postId={postId} />
+
+
+ <_NewAnswerForm postId={postId} />
+
+ Answers
+
<_AnswerList postId={postId} />
@@ -88,6 +95,22 @@ const _PostBody = styled(PostBody)`
margin-top: 64px;
`;
-const _AnswerList = styled(AnswerList)`
+const Rule = styled.hr`
+ margin: 64px 0;
+ border: none;
+ border-top: 1px #c8d6e5 solid;
+`;
+
+const _NewAnswerForm = styled(NewAnswerForm)`
margin-top: 64px;
`;
+
+const SectionHeading = styled.h2`
+ margin-top: 32px;
+ font-size: 28px;
+ font-weight: bold;
+`;
+
+const _AnswerList = styled(AnswerList)`
+ margin-top: 32px;
+`;
diff --git a/pages/404.tsx b/pages/404.tsx
new file mode 100644
index 0000000..8f17aae
--- /dev/null
+++ b/pages/404.tsx
@@ -0,0 +1,15 @@
+import Head from "next/head";
+import * as React from "react";
+import NotFoundPage from "@@/pageComponents/NotFoundPage";
+
+export default () => {
+ return (
+ <>
+
+ chipstackoverflow
+
+
+
+ >
+ );
+};
diff --git a/pages/__error.tsx b/pages/__error.tsx
new file mode 100644
index 0000000..567b681
--- /dev/null
+++ b/pages/__error.tsx
@@ -0,0 +1,21 @@
+// import * as React from "react";
+// import { NextPageContext } from "next";
+
+// interface Props extends React.Attributes {
+// statusCode: number;
+// }
+
+// /**
+// * Write a description here.
+// */
+// export default function ErrorH({ statusCode }: Props) {
+// return (
+
+// );
+// }
+
+// ErrorH.getInitialProps = ({ res, err }: NextPageContext) => {
+// const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
+
+// return { statusCode };
+// };
diff --git a/pages/api/post_images/[filename].ts b/pages/api/post_images/[filename].ts
new file mode 100644
index 0000000..cc71415
--- /dev/null
+++ b/pages/api/post_images/[filename].ts
@@ -0,0 +1,344 @@
+import { createCanvas, Image } from "canvas";
+import { NextApiRequest, NextApiResponse } from "next";
+import { getSingletonServerSideApolloClient } from "@@/repositories/apolloClient";
+import getPostById from "@@/repositories/getPostById";
+import { PostId } from "@@/models/Post";
+import Rank from "@@/models/Rank";
+import Suit from "@@/models/Suit";
+
+export default async (request: NextApiRequest, response: NextApiResponse) => {
+ const [postId, extension] =
+ `${request.query.filename}`.split(".") as [PostId, string];
+
+ if (extension !== "png") {
+ response.statusCode = 400;
+ response.end();
+
+ return;
+ }
+
+ const apolloClient = getSingletonServerSideApolloClient();
+ const post = await getPostById(postId as PostId, {
+ apolloClient,
+ authenticationToken: null,
+ });
+
+ if (!post) {
+ response.statusCode = 404;
+ response.end();
+
+ return;
+ }
+
+ const image = new Image();
+ image.src = TEMPLATE_SVG;
+
+ const canvas = createCanvas(1280, 800);
+ const ctx = canvas.getContext("2d");
+
+ // draw the template
+ ctx.drawImage(image, 0, 0);
+
+ // draw community cards
+ for (const [i, card] of post.hand.communityCards.entries()) {
+ const image = new Image();
+ image.src = CARD_SVGS.get(card.rank)!.get(card.suit)!;
+
+ ctx.drawImage(image, 336 + i * 128, 128, 96, 149);
+ }
+
+ // draw hero cards
+ for (const [i, card] of post.hand.playerCards
+ .get(post.heroIndex)!
+ .entries()) {
+ const image = new Image();
+ image.src = CARD_SVGS.get(card.rank)!.get(card.suit)!;
+
+ ctx.drawImage(image, 480 + i * 192, 373, 128, 199);
+ }
+
+ const buffer = canvas.toBuffer();
+
+ response.statusCode = 200;
+ response.setHeader("content-type", "image/png");
+ response.setHeader("content-length", buffer.length);
+ response.end(canvas.toBuffer("image/png"));
+};
+
+const TEMPLATE_SVG = `data:image/svg+xml,`;
+
+const CARD_SVGS = new Map([
+ [
+ Rank.ace,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.deuce,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.three,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.four,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.five,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.six,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.seven,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.eight,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.nine,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.ten,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.jack,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.queen,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+ [
+ Rank.king,
+ new Map([
+ [
+ Suit.spade,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.heart,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.diamond,
+ 'data:image/svg+xml,',
+ ],
+ [
+ Suit.club,
+ 'data:image/svg+xml,',
+ ],
+ ]),
+ ],
+]);
diff --git a/pages/posts/[postId].tsx b/pages/posts/[postId].tsx
index 85ce722..71d1fd8 100644
--- a/pages/posts/[postId].tsx
+++ b/pages/posts/[postId].tsx
@@ -1,5 +1,4 @@
import { GetStaticPropsContext } from "next";
-import Error from "next/error";
import Head from "next/head";
import { useRouter } from "next/router";
import * as React from "react";
@@ -8,6 +7,7 @@ import PostDetailPage from "@@/pageComponents/PostDetailPage";
import { getSingletonServerSideApolloClient } from "@@/repositories/apolloClient";
import getPostById from "@@/repositories/getPostById";
import { fromPost, toPost } from "@@/serializers/json/post";
+import NotFoundPage from "@@/pageComponents/NotFoundPage";
interface Props {
prerenderedPostJSON: Record | null;
@@ -19,7 +19,7 @@ export default ({ prerenderedPostJSON }: Props) => {
const post = prerenderedPostJSON ? toPost(prerenderedPostJSON) : null;
if (post === null && !isFallback) {
- return ;
+ return ;
}
return (
@@ -53,6 +53,5 @@ export async function getStaticProps({
props: {
prerenderedPostJSON: post ? fromPost(post) : null,
},
- unstable_revalidate: 1,
};
}