From 8dc22086f9b4fa0e7316284a26a28c4bdde180a9 Mon Sep 17 00:00:00 2001 From: Bart <45095973+barthuijgen@users.noreply.github.com> Date: Wed, 17 Mar 2021 10:33:51 +0100 Subject: [PATCH] Blueprint page refactor (#51) * blueprint page refactor * Deduplicate code on blueprint page Co-authored-by: Bart --- .../src/components/blueprint/Blueprint.tsx | 174 +++++++ .../components/blueprint/BlueprintBook.tsx | 256 ++++++++++ .../components/blueprint/BlueprintData.tsx | 63 +++ .../blueprint/BlueprintEntities.tsx | 54 +++ .../components/blueprint/BlueprintInfo.tsx | 66 +++ .../components/blueprint/BlueprintTags.tsx | 36 ++ .../components/blueprint/FavoriteButton.tsx | 40 ++ .../src/pages/blueprint/[blueprintId].tsx | 453 +----------------- 8 files changed, 710 insertions(+), 432 deletions(-) create mode 100644 apps/blueprints/src/components/blueprint/Blueprint.tsx create mode 100644 apps/blueprints/src/components/blueprint/BlueprintBook.tsx create mode 100644 apps/blueprints/src/components/blueprint/BlueprintData.tsx create mode 100644 apps/blueprints/src/components/blueprint/BlueprintEntities.tsx create mode 100644 apps/blueprints/src/components/blueprint/BlueprintInfo.tsx create mode 100644 apps/blueprints/src/components/blueprint/BlueprintTags.tsx create mode 100644 apps/blueprints/src/components/blueprint/FavoriteButton.tsx diff --git a/apps/blueprints/src/components/blueprint/Blueprint.tsx b/apps/blueprints/src/components/blueprint/Blueprint.tsx new file mode 100644 index 0000000..8ec2e54 --- /dev/null +++ b/apps/blueprints/src/components/blueprint/Blueprint.tsx @@ -0,0 +1,174 @@ +import React, { useEffect, useState } from "react"; +import BBCode from "bbcode-to-react"; +import { Grid, Image, Box } from "@chakra-ui/react"; +import { Blueprint as IBlueprint, BlueprintPage, BlueprintStringData } from "@factorio-sites/types"; +import { chakraResponsive, parseBlueprintStringClient } from "@factorio-sites/web-utils"; +import { Panel } from "../../components/Panel"; +import { Markdown } from "../../components/Markdown"; +import { CopyButton } from "../../components/CopyButton"; +import { ImageEditor } from "../../components/ImageEditor"; +import styled from "@emotion/styled"; +import { FavoriteButton } from "./FavoriteButton"; +import { useUrl } from "../../hooks/url.hook"; +import { BlueprintData } from "./BlueprintData"; +import { BlueprintInfo } from "./BlueprintInfo"; +import { BlueprintTags } from "./BlueprintTags"; +import { BlueprintEntities } from "./BlueprintEntities"; + +const StyledBlueptintPage = styled(Grid)` + grid-gap: 16px; + + .title { + position: relative; + width: 100%; + display: flex; + align-items: center; + + .text { + white-space: nowrap; + width: calc(100% - 120px); + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .panel { + &.image { + height: 579px; + } + &.child-tree { + overflow: hidden; + height: 579px; + position: relative; + .child-tree-wrapper { + height: 483px; + overflow: auto; + } + } + + &.tags { + text-align: left; + + .tag { + display: inline-block; + margin: 3px; + padding: 0 3px; + background: #313131; + border-radius: 3px; + } + } + + .description { + max-height: 600px; + } + } +`; + +const StyledMarkdown = styled(Markdown)` + max-height: 600px; +`; + +interface BlueprintProps { + blueprint: IBlueprint; + blueprint_page: BlueprintPage; + favorite: boolean; +} + +export const BlueprintSubPage: React.FC = ({ + blueprint, + blueprint_page, + favorite, +}) => { + const url = useUrl(); + const [string, setString] = useState(null); + const [data, setData] = useState(null); + + useEffect(() => { + fetch(`/api/string/${blueprint.blueprint_hash}`) + .then((res) => res.text()) + .then((string) => { + setString(string); + const data = parseBlueprintStringClient(string); + setData(data); + }) + .catch((reason) => console.error(reason)); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + + Image + Factorio blueprint editor + + {string && ( + + )} + {blueprint.blueprint_hash && url && ( + + )} + + + } + > + {string && } + + + + {blueprint_page.title} + + + } + > + {blueprint_page.description_markdown} + + + + + + + + + + + + Entities for{" "} + {data?.blueprint?.label ? BBCode.toReact(data.blueprint.label) : "blueprint"} + + } + > + {data && } + + + + {string && data && } + + + ); +}; diff --git a/apps/blueprints/src/components/blueprint/BlueprintBook.tsx b/apps/blueprints/src/components/blueprint/BlueprintBook.tsx new file mode 100644 index 0000000..00888be --- /dev/null +++ b/apps/blueprints/src/components/blueprint/BlueprintBook.tsx @@ -0,0 +1,256 @@ +import React, { useEffect, useState } from "react"; +import BBCode from "bbcode-to-react"; +import { Image, Box, Grid } from "@chakra-ui/react"; +import styled from "@emotion/styled"; +import { + BlueprintBook, + Blueprint, + BlueprintPage, + BlueprintStringData, +} from "@factorio-sites/types"; +import { + chakraResponsive, + ChildTreeBlueprintBookEnriched, + mergeBlueprintDataAndChildTree, + parseBlueprintStringClient, +} from "@factorio-sites/web-utils"; +import { Panel } from "../../components/Panel"; +import { Markdown } from "../../components/Markdown"; +import { BookChildTree } from "../../components/BookChildTree"; +import { CopyButton } from "../../components/CopyButton"; +import { ImageEditor } from "../../components/ImageEditor"; +import { useUrl } from "../../hooks/url.hook"; +import { FavoriteButton } from "./FavoriteButton"; +import { BlueprintData } from "./BlueprintData"; +import { BlueprintInfo } from "./BlueprintInfo"; +import { BlueprintTags } from "./BlueprintTags"; +import { BlueprintEntities } from "./BlueprintEntities"; + +const StyledBlueptintPage = styled(Grid)` + grid-gap: 16px; + + .title { + position: relative; + width: 100%; + display: flex; + align-items: center; + + .text { + white-space: nowrap; + width: calc(100% - 120px); + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .panel { + &.image { + height: 579px; + } + &.child-tree { + overflow: hidden; + height: 579px; + position: relative; + .child-tree-wrapper { + height: 483px; + overflow: auto; + } + } + + .description { + max-height: 600px; + } + } +`; + +const StyledMarkdown = styled(Markdown)` + max-height: 600px; +`; + +type Selected = + | { type: "blueprint"; data: Pick } + | { type: "blueprint_book"; data: Pick }; + +interface BlueprintBookSubPageProps { + selected: Selected; + blueprint_book: BlueprintBook; + blueprint_page: BlueprintPage; + favorite: boolean; +} + +export const BlueprintBookSubPage: React.FC = ({ + selected, + blueprint_book, + blueprint_page, + favorite, +}) => { + const url = useUrl(); + const [selectedBlueprintString, setSelectedBlueprintString] = useState(null); + const [bookChildTreeData, setBookChildTreeData] = useState( + null + ); + const [selectedData, setSelectedData] = useState(null); + const selectedHash = selected.data.blueprint_hash; + const showEntities = selected.type === "blueprint" && selectedData?.blueprint; + + useEffect(() => { + fetch(`/api/string/${blueprint_book.blueprint_hash}`) + .then((res) => res.text()) + .then((string) => { + const data = parseBlueprintStringClient(string); + if (data) { + setBookChildTreeData( + mergeBlueprintDataAndChildTree(data, { + id: blueprint_book.id, + name: blueprint_book.label, + type: "blueprint_book", + children: blueprint_book.child_tree, + }) + ); + } + }) + .catch((reason) => console.error(reason)); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + fetch(`/api/string/${selectedHash}`) + .then((res) => res.text()) + .then((string) => { + setSelectedBlueprintString(string); + if (selected.type === "blueprint") { + const data = parseBlueprintStringClient(string); + setSelectedData(data); + } else { + setSelectedData(null); + } + }) + .catch((reason) => console.error(reason)); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedHash]); + + const onRequestData = () => { + fetch(`/api/string/${selectedHash}`) + .then((res) => res.text()) + .then((string) => { + const data = parseBlueprintStringClient(string); + setSelectedData(data); + }); + }; + + return ( + + + {blueprint_page.title} + + + } + gridColumn="1" + gridRow="1" + > + {bookChildTreeData && ( +
+ +
+ )} +
+ + + Image + Factorio blueprint editor + + {selectedBlueprintString && ( + + )} + {selected.data.blueprint_hash && url && ( + + )} + + + } + > + {selectedBlueprintString && } + + + + Description + + + } + > + {blueprint_page.description_markdown} + + + + + + + + + + + {showEntities && ( + + Entities for{" "} + {selectedData?.blueprint?.label + ? BBCode.toReact(selectedData.blueprint.label) + : "blueprint"} + + } + > + {selectedData && } + + )} + + + {selectedBlueprintString && ( + + )} + +
+ ); +}; diff --git a/apps/blueprints/src/components/blueprint/BlueprintData.tsx b/apps/blueprints/src/components/blueprint/BlueprintData.tsx new file mode 100644 index 0000000..7ab2b8d --- /dev/null +++ b/apps/blueprints/src/components/blueprint/BlueprintData.tsx @@ -0,0 +1,63 @@ +import { Button } from "../Button"; +import { Box } from "@chakra-ui/react"; +import { useEffect, useState } from "react"; +import { BlueprintStringData } from "@factorio-sites/types"; + +interface BlueprintDataProps { + string: string; + data: BlueprintStringData | null; + onRequestData?: () => void; +} + +export const BlueprintData: React.FC = ({ string, data, onRequestData }) => { + const [showDetails, setShowDetails] = useState<"string" | "json" | "none">("none"); + + useEffect(() => { + setShowDetails("none"); + }, [string, data]); + + return ( + + + + + + + {showDetails === "string" && ( +