From 6d3aae7fe9c3c65d4a425afa5ce681478c9660cc Mon Sep 17 00:00:00 2001 From: Sebastian Seedorf Date: Tue, 9 Aug 2022 12:24:47 +0200 Subject: [PATCH] Added entity span --- components/EntityIcon.module.css | 27 ++++++++++++ components/EntityIcon.tsx | 29 +++++++++++++ components/EntitySpan.module.css | 73 ++++++++++++++++++++++++++++++++ components/EntitySpan.tsx | 47 ++++++++++++++++++++ components/Group.tsx | 21 +++++---- components/Home.module.css | 10 +++++ components/Home.tsx | 23 ++++++---- components/LeftClickIcon.tsx | 16 +++++++ components/Recipe.module.css | 5 +++ components/Recipe.tsx | 23 ++++++++++ package.json | 3 +- yarn.lock | 15 ++++++- 12 files changed, 270 insertions(+), 22 deletions(-) create mode 100644 components/EntityIcon.module.css create mode 100644 components/EntityIcon.tsx create mode 100644 components/EntitySpan.module.css create mode 100644 components/EntitySpan.tsx create mode 100644 components/LeftClickIcon.tsx create mode 100644 components/Recipe.module.css create mode 100644 components/Recipe.tsx diff --git a/components/EntityIcon.module.css b/components/EntityIcon.module.css new file mode 100644 index 0000000..4f0f2f8 --- /dev/null +++ b/components/EntityIcon.module.css @@ -0,0 +1,27 @@ +.span { + background: #DDD; + font-size: 2em; + border: 1px solid white; + display: inline-block; + position: relative; +} + +.amount { + position: absolute; + inset-inline-end: 0.2em; + inset-block-end: 0; + font-size: 50%; + color: white; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; +} + +.img { + display: inline-block; + width: 1em; + height: 1em; + margin-inline-end: 0.2em; +} + +.strong { + font-weight: 600; +} diff --git a/components/EntityIcon.tsx b/components/EntityIcon.tsx new file mode 100644 index 0000000..c6aa94d --- /dev/null +++ b/components/EntityIcon.tsx @@ -0,0 +1,29 @@ +import {FC, HTMLProps, useMemo} from "react" +import {Entity} from "../src/types" +import {useDetails} from "../src/hooks/useDetails" +import styles from './EntityIcon.module.css' + +interface Props extends Omit, 'value'> { + value: Entity|string + amount?: number +} + +export const EntityIcon: FC = ({value, amount, ...rest}) => { + const details = useDetails() + const entity = useMemo(() => { + return typeof value === "object" + ? value + : details.find(detail => detail.href === value) ?? { + href: value, + name: value, + image: value, + recipe: undefined + } + }, [details, value]) + + return + {/* eslint-disable-next-line @next/next/no-img-element */} + {entity.name}/ + {amount !== undefined && {amount}} + +} diff --git a/components/EntitySpan.module.css b/components/EntitySpan.module.css new file mode 100644 index 0000000..3e0be9e --- /dev/null +++ b/components/EntitySpan.module.css @@ -0,0 +1,73 @@ +.span { + background: #DDD; + font-size: 1em; + border: 1px solid white; + display: inline-block; + position: relative; +} + +.tooltip { + --background: lightsalmon; + --arrow-width: 0.6em; + --arrow-height: 0.4em; + display: none; + position: absolute; + left: calc(100% + var(--arrow-width)); + top: -500%; + bottom: -500%; + margin: auto 0; + width: max-content; + height: max-content; + background: var(--background); + padding: 0.5em; + border-radius: 0.7em; + z-index: 1; +} + +.span:hover > .tooltip { + display: initial; +} + +.tooltip::before { + content: ""; + border-style: solid; + top: -500%; + bottom: -500%; + margin: auto 0; + height: max-content; + border-width: var(--arrow-height) var(--arrow-width) var(--arrow-height) 0; + border-color: transparent var(--background) transparent transparent; + position: absolute; + left: calc(var(--arrow-width) * -1 + 1px); +} + +.img { + display: inline-block; + width: 1em; + height: 1em; + margin-inline-end: 0.2em; + transform: translateY(0.1em); +} + +.strong { + font-weight: 600; + margin-block: 1em 0.4em; +} + +.strong:first-child { + margin-block-start: 0; +} + +.leftClick { + height: 1em; + transform: translateY(0.1em); +} + +.rightClick { + height: 1em; + transform: scaleX(-1) translateY(0.1em); +} + +.clickBtn { + fill: red; +} diff --git a/components/EntitySpan.tsx b/components/EntitySpan.tsx new file mode 100644 index 0000000..645ad96 --- /dev/null +++ b/components/EntitySpan.tsx @@ -0,0 +1,47 @@ +import {FC, HTMLProps, useMemo} from "react" +import {Entity} from "../src/types" +import {useDetails} from "../src/hooks/useDetails" +import styles from './EntitySpan.module.css' +import {RecipeSpan} from "./Recipe"; +import {LeftClickIcon} from "./LeftClickIcon"; + +interface Props extends Omit, 'value'> { + value: Entity|string + leftClickText?: string + rightClickText?: string +} + +export const EntitySpan: FC = ({value, leftClickText, rightClickText, ...rest}) => { + const details = useDetails() + const entity = useMemo(() => { + return typeof value === "object" + ? value + : details.find(detail => detail.href === value) ?? { + href: value, + name: value, + image: value, + recipe: undefined + } + }, [details, value]) + + return + {/* eslint-disable-next-line @next/next/no-img-element */} + {entity.name}/ + {entity.name} +
+ {entity.recipe && ( + <> +
Recipe
+ + + )} + {(leftClickText || rightClickText) && ( + <> +
Actions
+ {leftClickText &&
{leftClickText}
} + {rightClickText &&
{rightClickText}
} + + )} +
+
+} diff --git a/components/Group.tsx b/components/Group.tsx index 1e6250e..194b929 100644 --- a/components/Group.tsx +++ b/components/Group.tsx @@ -3,6 +3,7 @@ import {FactorySelect} from "./FactorySelect"; import {useDetails} from "../src/hooks/useDetails"; import {Entity} from "../src/types"; import styles from "./Group.module.css" +import {EntitySpan} from "./EntitySpan"; interface Props { onRemove: () => void @@ -109,13 +110,12 @@ export const Group: FC = ({

Inputs

@@ -123,17 +123,16 @@ export const Group: FC = ({

Suggestions

diff --git a/components/Home.module.css b/components/Home.module.css index e0ad86f..0ddb197 100644 --- a/components/Home.module.css +++ b/components/Home.module.css @@ -2,3 +2,13 @@ display: grid; grid-template-columns: repeat(auto-fit, minmax(500px, max-content)); } + +.missingFactories { + display: flex; + flex-wrap: wrap; + gap: 0.1em; +} + +.missingFactories > * { + width: max-content; +} diff --git a/components/Home.tsx b/components/Home.tsx index 29920ea..d64025b 100644 --- a/components/Home.tsx +++ b/components/Home.tsx @@ -7,6 +7,7 @@ import {sortByProperty} from "../src/utils"; import {useDetails} from "../src/hooks/useDetails"; import {Entity} from "../src/types"; import pako from 'pako'; +import {EntitySpan} from "./EntitySpan"; interface Group { name: string @@ -108,15 +109,19 @@ export const HomeComponent: FC = () => {
Missing factories -
    - { - missingFactories.map(missing =>
  • { - event.preventDefault() - setExcludedSuggestions([...excludedSuggestions, missing.href]) - }}>{missing.name}
  • ) - } -
+
+ { missingFactories.map(missing => ( + { + event.preventDefault() + setExcludedSuggestions([...excludedSuggestions, missing.href]) + }} + rightClickText={"Exclude this recipe from suggestions"} + /> + ))} +
{ diff --git a/components/LeftClickIcon.tsx b/components/LeftClickIcon.tsx new file mode 100644 index 0000000..7b9cf28 --- /dev/null +++ b/components/LeftClickIcon.tsx @@ -0,0 +1,16 @@ +import {FC} from "react"; + +interface Props { + className?: string + classBody?: string + classClick?: string +} + +export const LeftClickIcon: FC = ({className, classBody, classClick}) => { + return ( + + + + + ) +} diff --git a/components/Recipe.module.css b/components/Recipe.module.css new file mode 100644 index 0000000..85b7639 --- /dev/null +++ b/components/Recipe.module.css @@ -0,0 +1,5 @@ +.recipe { + align-items: center; + display: flex; + gap: 0.2em; +} diff --git a/components/Recipe.tsx b/components/Recipe.tsx new file mode 100644 index 0000000..08fe05f --- /dev/null +++ b/components/Recipe.tsx @@ -0,0 +1,23 @@ +import {FC} from "react" +import {Recipe} from "../src/types" +import {EntityIcon} from "./EntityIcon"; +import styles from './Recipe.module.css' + +interface Props { + recipe: Recipe +} + +export const RecipeSpan: FC = ({recipe}) => { + const joinByPlus = (elems: JSX.Element[]) => elems.reduce((acc, curr) => { + if (acc.length) { + return [...acc, '+', curr] + } else { + return [curr] + } + }, [] as (JSX.Element|string)[]) + const before = Object.entries({...recipe.prerequisites}).map(([key, amount]) => ) + const after = Object.entries({...recipe.output}).map(([key, amount]) => ) + return + {joinByPlus(before)} → {joinByPlus(after)} + +} diff --git a/package.json b/package.json index ec4664f..e9bc079 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "pako": "^2.0.4", "react": "18.2.0", "react-dom": "18.2.0", - "react-select": "^5.4.0" + "react-select": "^5.4.0", + "react-tooltip": "^4.2.21" }, "devDependencies": { "@types/node": "18.6.4", diff --git a/yarn.lock b/yarn.lock index a874d04..fb578ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1727,7 +1727,7 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1: +prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -1772,6 +1772,14 @@ react-select@^5.4.0: prop-types "^15.6.0" react-transition-group "^4.3.0" +react-tooltip@^4.2.21: + version "4.2.21" + resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-4.2.21.tgz#840123ed86cf33d50ddde8ec8813b2960bfded7f" + integrity sha512-zSLprMymBDowknr0KVDiJ05IjZn9mQhhg4PRsqln0OZtURAJ1snt1xi5daZfagsh6vfsziZrc9pErPTDY1ACig== + dependencies: + prop-types "^15.7.2" + uuid "^7.0.3" + react-transition-group@^4.3.0: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" @@ -2071,6 +2079,11 @@ use-sync-external-store@1.2.0: resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== +uuid@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" + integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"