diff --git a/apps/blueprints/src/components/FactorioCode.tsx b/apps/blueprints/src/components/FactorioCode.tsx index 2b57ed9..9070100 100644 --- a/apps/blueprints/src/components/FactorioCode.tsx +++ b/apps/blueprints/src/components/FactorioCode.tsx @@ -42,8 +42,6 @@ const parseFactorioCode = (string: string): ReactNode => { if (!iconMatches.length) return {string}; - // console.log(string, iconMatches); - const result = [] as ReactNode[]; let lastHandledIndex = 0; @@ -73,7 +71,6 @@ const parseFactorioCode = (string: string): ReactNode => { match.groups.type = type; match.groups.icon = icon; } - console.log(match); } result.push( = ({ alt, src }) => scale: 0.9, translation: { x: window.innerWidth * 0.05, y: 30 }, }); - console.log(src); return ( <> diff --git a/apps/blueprints/src/components/ImageEditor.tsx b/apps/blueprints/src/components/ImageEditor.tsx index b4e75b7..df47095 100644 --- a/apps/blueprints/src/components/ImageEditor.tsx +++ b/apps/blueprints/src/components/ImageEditor.tsx @@ -25,9 +25,10 @@ const editorCss = css` interface ImageEditorProps { string: string; + onError?: () => void; } -export const ImageEditor: React.FC = ({ string }) => { +export const ImageEditor: React.FC = ({ string, onError }) => { const canvasRef = useRef(null); // const [image, setImage] = useState(); const FbeRef = useRef(); @@ -89,13 +90,14 @@ export const ImageEditor: React.FC = ({ string }) => { // setImage(URL.createObjectURL(picture)); } catch (reason) { setRenderError(true); + if (onError) onError(); if (Array.isArray(reason.errors)) { return console.error("Blueprint string not supported by FBE", reason.errors); } console.error("Failed to render blueprint", reason); } })(); - }, [string, editorLoaded]); + }, [string, editorLoaded, onError]); return (
diff --git a/apps/blueprints/src/components/blueprint/Blueprint.tsx b/apps/blueprints/src/components/blueprint/Blueprint.tsx index e641e1b..3ef959b 100644 --- a/apps/blueprints/src/components/blueprint/Blueprint.tsx +++ b/apps/blueprints/src/components/blueprint/Blueprint.tsx @@ -5,7 +5,6 @@ import { chakraResponsive, parseBlueprintStringClient } from "@factorio-sites/we 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"; @@ -13,9 +12,7 @@ import { BlueprintData } from "./BlueprintData"; import { BlueprintInfo } from "./BlueprintInfo"; import { BlueprintTags } from "./BlueprintTags"; import { BlueprintEntities } from "./BlueprintEntities"; -import { useCookies } from "react-cookie"; -import { FullscreenImage } from "../FullscreenImage"; -import { isMobileBrowser } from "../../utils/navigator.utils"; +import { BlueprintImage, RENDERERS } from "./BlueprintImage"; const StyledBlueptintPage = styled(Grid)` grid-gap: 16px; @@ -58,8 +55,7 @@ export const BlueprintSubPage: React.FC = ({ const url = useUrl(); const [string, setString] = useState(null); const [data, setData] = useState(null); - const [cookies] = useCookies(); - const isFbeRenderer = cookies.renderer !== "fbsr" && !isMobileBrowser(); + const [renderer, setRenderer] = useState(null); useEffect(() => { fetch(`/api/string/${blueprint.blueprint_hash}`) @@ -84,7 +80,7 @@ export const BlueprintSubPage: React.FC = ({ title={ <> Image - {isFbeRenderer && ( + {renderer === "fbe" && ( Factorio blueprint editor = ({ } > - {string && - (isFbeRenderer ? ( - - ) : ( - - ))} + {string && ( + + )} = ({ null ); const [selectedData, setSelectedData] = useState(null); - const [cookies] = useCookies(); - const isFbeRenderer = cookies.renderer !== "fbsr" && !isMobileBrowser(); + const [renderer, setRenderer] = useState(null); const selectedHash = selected.data.blueprint_hash; const showEntities = selected.type === "blueprint" && selectedData?.blueprint; @@ -163,7 +159,7 @@ export const BlueprintBookSubPage: React.FC = ({ title={ <> Image - {isFbeRenderer && ( + {renderer === "fbe" && ( Factorio blueprint editor = ({ } > - {selectedBlueprintString && - (isFbeRenderer ? ( - - ) : ( - - ))} - - {/* {selectedBlueprintString && } */} + {selectedBlueprintString && ( + + )} void; +} + +export const BlueprintImage: React.FC = ({ + string, + blueprint_hash, + label, + onSetRenderer, +}) => { + const width = useWindowWidth(); + const [cookies] = useCookies(); + + const determineRenderer = () => { + const isFbeRenderer = cookies.renderer !== "fbsr" && width > 760; + return isFbeRenderer ? "fbe" : "fbsr"; + }; + + const [renderer, setRenderer] = useState(determineRenderer); + + useEffect(() => { + setRenderer(determineRenderer()); + if (onSetRenderer) onSetRenderer(determineRenderer()); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [blueprint_hash]); + + return renderer === "fbe" ? ( + setRenderer("fbsr")}> + ) : ( + + ); +}; diff --git a/apps/blueprints/src/hooks/window.hooks.ts b/apps/blueprints/src/hooks/window.hooks.ts new file mode 100644 index 0000000..360f777 --- /dev/null +++ b/apps/blueprints/src/hooks/window.hooks.ts @@ -0,0 +1,42 @@ +import { useState, useEffect } from "react"; + +type TimeoutType = ReturnType | null; + +const RESIZE_DEBOUNCE_MS = 100; + +function getWidth() { + return typeof window !== "undefined" + ? window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth + : 0; +} + +export function useWindowWidth() { + const [width, setWidth] = useState(getWidth()); + + let isMounted = false; + + useEffect(() => { + let timeoutId: TimeoutType = null; + const reesizeListener = () => { + if (timeoutId) { + clearTimeout(timeoutId); + timeoutId = null; + } + timeoutId = setTimeout(() => { + if (isMounted) { + setWidth(getWidth()); + } + }, RESIZE_DEBOUNCE_MS); + }; + + window.addEventListener("resize", reesizeListener); + + return () => { + // eslint-disable-next-line react-hooks/exhaustive-deps + isMounted = false; + window.removeEventListener("resize", reesizeListener); + }; + }); + + return width; +} diff --git a/apps/blueprints/src/pages/index.tsx b/apps/blueprints/src/pages/index.tsx index 5df6be5..fe8c24b 100644 --- a/apps/blueprints/src/pages/index.tsx +++ b/apps/blueprints/src/pages/index.tsx @@ -21,19 +21,33 @@ import { Stack, Radio, Checkbox, + useBreakpoint, } from "@chakra-ui/react"; import { css } from "@emotion/react"; import { MdSearch } from "react-icons/md"; import { TAGS } from "@factorio-sites/common-utils"; +import { mq } from "@factorio-sites/web-utils"; const pageCss = css({ display: "flex", + flexDirection: "column", + [mq[0]]: { + flexDirection: "row", + }, }); const sidebarCss = css({ - borderRight: "1px solid #b7b7b7", - paddingRight: "1rem", - marginRight: "1rem", - width: "233px", + borderBottom: "1px solid #b7b7b7", + paddingBottom: "1rem", + marginBottom: "1rem", + [mq[0]]: { + borderRight: "1px solid #b7b7b7", + marginRight: "1rem", + paddingRight: "1rem", + borderBottom: "none", + paddingBottom: "0", + marginBottom: "0", + width: "233px", + }, }); const SidebarRow = css({ marginTop: "1rem", @@ -67,6 +81,8 @@ export const Index: NextPage = ({ const [searchQuery, setSearchQuery] = useState(""); const routerQueryToHref = useRouterQueryToHref(); const data = useFbeData(); + const bp = useBreakpoint(); + console.log({ bp }); useEffect(() => { setSearchQuery((router.query.q as string) || ""); diff --git a/apps/blueprints/src/pages/user/edit.tsx b/apps/blueprints/src/pages/user/edit.tsx index 963954f..d783ee0 100644 --- a/apps/blueprints/src/pages/user/edit.tsx +++ b/apps/blueprints/src/pages/user/edit.tsx @@ -98,6 +98,8 @@ export const UserEdit: NextPage = () => { setCookie("renderer", value, { path: "/", expires: addYears(new Date(), 1), + sameSite: "strict", + secure: process.env.NODE_ENV === "production", }) } value={cookies.renderer || "fbe"} diff --git a/libs/web-utils/src/lib/web-utils.ts b/libs/web-utils/src/lib/web-utils.ts index 62df18a..2359d09 100644 --- a/libs/web-utils/src/lib/web-utils.ts +++ b/libs/web-utils/src/lib/web-utils.ts @@ -112,3 +112,7 @@ export function chakraResponsive({ }): Array { return [mobile, mobile, desktop, desktop]; } + +const breakpoints = ["30em", "48em", "62em", "80em"]; + +export const mq = breakpoints.map((bp) => `@media (min-width: ${bp})`);