diff --git a/package.json b/package.json index f58a9ea..2ea3d8a 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "dependencies": { "@chakra-ui/react": "^3.2.1", "@emotion/react": "^11.13.5", + "@fontsource/ibm-plex-sans": "^5.1.0", "@turf/bbox": "^7.1.0", "d3": "^7.9.0", "jotai": "^2.10.3", diff --git a/src/App.jsx b/src/App.jsx index 9a04316..86fe715 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,32 +1,42 @@ -import { Box, Grid } from "@chakra-ui/react"; +import { Box, Grid, Text } from "@chakra-ui/react"; import Providers from "./Providers"; import { ChatInput, ChatOutput, Map } from "./components"; function App() { return ( - - - - - - - - + + Land Carbon Lab - Zeno + + + + + + + + + + + + + ); diff --git a/src/components/ChatInput.jsx b/src/components/ChatInput.jsx index 901b256..aeff784 100644 --- a/src/components/ChatInput.jsx +++ b/src/components/ChatInput.jsx @@ -1,5 +1,6 @@ import { useState } from "react"; -import { Input } from "@chakra-ui/react"; +import { Box, Button, Input } from "@chakra-ui/react"; +import { MdChevronRight } from "react-icons/md"; import { useSetAtom } from "jotai"; import { addPrompt } from "../atoms"; @@ -17,14 +18,33 @@ function ChatInput() { }; return ( - setInputValue(e.target.value)} - onKeyUp={handleKeyUp} - /> + + setInputValue(e.target.value)} + onKeyUp={handleKeyUp} + /> + + ); } diff --git a/src/components/ChatOutput.jsx b/src/components/ChatOutput.jsx index f096463..eae1943 100644 --- a/src/components/ChatOutput.jsx +++ b/src/components/ChatOutput.jsx @@ -31,7 +31,7 @@ function ChatOutput() { }, []); return ( - + {chatHistory.map((msg) => { switch (msg.type) { case "in": diff --git a/src/components/LclLogo.jsx b/src/components/LclLogo.jsx new file mode 100644 index 0000000..5604bb3 --- /dev/null +++ b/src/components/LclLogo.jsx @@ -0,0 +1,15 @@ +function LclLogo() { + return ( + + + + + + + + + + ); +} + +export default LclLogo; diff --git a/src/components/Map.jsx b/src/components/Map.jsx index 71f5a01..e551cf7 100644 --- a/src/components/Map.jsx +++ b/src/components/Map.jsx @@ -1,5 +1,9 @@ import "maplibre-gl/dist/maplibre-gl.css"; -import MapGl, { Layer, Source, AttributionControl } from "react-map-gl/maplibre"; +import MapGl, { + Layer, + Source, + AttributionControl, +} from "react-map-gl/maplibre"; import { useEffect } from "react"; import bbox from "@turf/bbox"; import { mapLayersAtom } from "../atoms"; @@ -19,19 +23,28 @@ function Map() { // each layer is a feature collection, so we need to calculate the bounds of all features useEffect(() => { if (mapLayers.length > 0) { - const bounds = mapLayers.reduce((acc, layer) => { - const layerBounds = bbox(layer); - return [ - Math.min(acc[0], layerBounds[0]), - Math.min(acc[1], layerBounds[1]), - Math.max(acc[2], layerBounds[2]), - Math.max(acc[3], layerBounds[3]) - ]; - }, [Infinity, Infinity, -Infinity, -Infinity]); + const bounds = mapLayers.reduce( + (acc, layer) => { + const layerBounds = bbox(layer); + return [ + Math.min(acc[0], layerBounds[0]), + Math.min(acc[1], layerBounds[1]), + Math.max(acc[2], layerBounds[2]), + Math.max(acc[3], layerBounds[3]), + ]; + }, + [Infinity, Infinity, -Infinity, -Infinity] + ); - mapRef.current.fitBounds([[bounds[0], bounds[1]], [bounds[2], bounds[3]]], { - padding: {top: 100, bottom: 100, left: 450, right: 100} - }); + mapRef.current.fitBounds( + [ + [bounds[0], bounds[1]], + [bounds[2], bounds[3]], + ], + { + padding: 100, + } + ); } }, [mapLayers]); @@ -48,19 +61,28 @@ function Map() { - {mapLayers.map((layer, idx) => { - const layerId = layer?.features[0]?.id || idx; - return ( - - - - ); - })} + {mapLayers.map((layer, idx) => { + const layerId = layer?.features[0]?.id || idx; + return ( + + + + + ); + })} ); diff --git a/src/components/MessageIn.jsx b/src/components/MessageIn.jsx index 5c64b3d..de64a02 100644 --- a/src/components/MessageIn.jsx +++ b/src/components/MessageIn.jsx @@ -3,7 +3,7 @@ import { Box } from "@chakra-ui/react"; function MessageIn({ message }) { return ( - + {message} ); diff --git a/src/components/MessageAssistant.jsx b/src/components/MessageOut/MessageAssistant.jsx similarity index 67% rename from src/components/MessageAssistant.jsx rename to src/components/MessageOut/MessageAssistant.jsx index ec603e4..180c37c 100644 --- a/src/components/MessageAssistant.jsx +++ b/src/components/MessageOut/MessageAssistant.jsx @@ -1,32 +1,44 @@ import T from "prop-types"; -import { Box, Button } from "@chakra-ui/react"; +import { Button } from "@chakra-ui/react"; import Markdown from "react-markdown"; import { useSetAtom } from "jotai"; -import { addPrompt } from "../atoms"; +import { addPrompt } from "../../atoms"; +import MessageOutWrapper from "./wrapper"; function MessageAssistant({ message }) { const submit = useSetAtom(addPrompt); if (typeof message === "string" || message instanceof String) { return ( - + {message} - + ); } else { return ( - + {message.map((messagePart) => { const { index, type } = messagePart; if (type === "text") { return {messagePart.text}; } else { const { query } = JSON.parse(messagePart.partial_json); - return ; + return ( + ); } })} - + ); } } diff --git a/src/components/MessageDefault.jsx b/src/components/MessageOut/MessageDefault.jsx similarity index 67% rename from src/components/MessageDefault.jsx rename to src/components/MessageOut/MessageDefault.jsx index 9aecd9c..8934ed6 100644 --- a/src/components/MessageDefault.jsx +++ b/src/components/MessageOut/MessageDefault.jsx @@ -1,13 +1,13 @@ import T from "prop-types"; -import { Box } from "@chakra-ui/react"; -import { Alert } from "./ui/alert"; +import { Alert } from "../ui/alert"; +import MessageOutWrapper from "./wrapper"; function MessageDefault({message, type}) { return ( - + {message} - + ); } diff --git a/src/components/MessageTool.jsx b/src/components/MessageOut/MessageTool.jsx similarity index 92% rename from src/components/MessageTool.jsx rename to src/components/MessageOut/MessageTool.jsx index 3c637e5..adb066d 100644 --- a/src/components/MessageTool.jsx +++ b/src/components/MessageOut/MessageTool.jsx @@ -1,10 +1,11 @@ import T from "prop-types"; import { Box, Button } from "@chakra-ui/react"; -import MiniMap from "./MiniMap"; -import BarChart from "./BarChart"; +import MessageOutWrapper from "./wrapper"; +import MiniMap from "../MiniMap"; +import BarChart from "../BarChart"; import { useSetAtom } from "jotai"; -import { mapLayersAtom } from "../atoms"; +import { mapLayersAtom } from "../../atoms"; function ContextLayer({message}) { return ( @@ -93,9 +94,9 @@ function MessageTool({message, toolName, artifact}) { } return ( - + {render} - + ); } diff --git a/src/components/MessageOut/wrapper.jsx b/src/components/MessageOut/wrapper.jsx new file mode 100644 index 0000000..69103cd --- /dev/null +++ b/src/components/MessageOut/wrapper.jsx @@ -0,0 +1,22 @@ +import T from "prop-types"; +import { Box } from "@chakra-ui/react"; +import { LclLogo } from ".."; + +function MessageOutWrapper({ children }) { + return ( + + + + + + {children} + + + ); +} + +MessageOutWrapper.propTypes = { + children: T.node.isRequired +}; + +export default MessageOutWrapper; diff --git a/src/components/MiniMap.jsx b/src/components/MiniMap.jsx index 4d6fa5e..394c13f 100644 --- a/src/components/MiniMap.jsx +++ b/src/components/MiniMap.jsx @@ -4,7 +4,7 @@ import "maplibre-gl/dist/maplibre-gl.css"; import bbox from "@turf/bbox"; /** - * MiniMap is a static map for the sidebar + * MiniMap is a static map for the sidebar */ function MiniMap({ artifact }){ let viewState = { @@ -34,7 +34,7 @@ function MiniMap({ artifact }){ @@ -45,7 +45,16 @@ function MiniMap({ artifact }){ type="geojson" data={artifact} > - + + )} diff --git a/src/components/index.js b/src/components/index.js index 458c59f..c31e52a 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,14 +1,16 @@ import ChatInput from "./ChatInput"; import ChatOutput from "./ChatOutput"; +import LclLogo from "./LclLogo"; import Map from "./Map"; import MessageIn from "./MessageIn"; -import MessageTool from "./MessageTool"; -import MessageAssistant from "./MessageAssistant"; -import MessageDefault from "./MessageDefault"; +import MessageTool from "./MessageOut/MessageTool"; +import MessageAssistant from "./MessageOut/MessageAssistant"; +import MessageDefault from "./MessageOut/MessageDefault"; export { ChatInput, ChatOutput, + LclLogo, Map, MessageIn, MessageTool, diff --git a/src/main.jsx b/src/main.jsx index b48d3a0..c0577bb 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,6 +1,7 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; +import "@fontsource/ibm-plex-sans/index.css"; createRoot(document.getElementById("root")).render( diff --git a/src/theme/globalCss.jsx b/src/theme/globalCss.jsx new file mode 100644 index 0000000..e2c98e7 --- /dev/null +++ b/src/theme/globalCss.jsx @@ -0,0 +1,21 @@ +export default { + h2: { + marginBottom: 4, + fontSize: "lg", + fontWeight: "bold" + }, + h3: { + marginBottom: 4, + fontWeight: "bold" + }, + ul: { + marginTop: 4, + marginBottom: 4, + listStyleType: "disc", + paddingLeft: 4 + }, + p: { + marginTop: 4, + marginBottom: 4, + } +}; diff --git a/src/theme/index.jsx b/src/theme/index.jsx index b6722c6..51b8c4a 100644 --- a/src/theme/index.jsx +++ b/src/theme/index.jsx @@ -1,5 +1,54 @@ -import { createSystem, defaultConfig } from "@chakra-ui/react"; +import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"; +import globalCss from "./globalCss"; -const config = {}; +const config = defineConfig({ + globalCss, + theme: { + tokens: { + fonts: { + body: { value: "IBM Plex Sans" }, + heading: { value: "IBM Plex Sans" }, + }, + colors: { + blue: { + 50: "#ebf9ff", + 100: "#d1f1ff", + 200: "#aee7ff", + 300: "#76dbff", + 400: "#35c4ff", + 500: "#07a0ff", + 600: "#007bff", + 700: "#0062ff", + 800: "#0051d7", + 900: "#0049a8", //primary + 950: "#062d65", + }, + + lime: { + 50: "#fcfee7", + 100: "#f7fbcc", + 200: "#eef89e", + 300: "#def066", + 400: "#cbe437", + 500: "#adca18", //primary + 600: "#87a10f", + 700: "#667b10", + 800: "#516113", + 900: "#445215", + 950: "#242e05", + }, + cyan: { 500: "#01B9F3" }, + indigo: { 500: "#6F6FDF" }, + purple: { 500: "#BA4AFF" }, + pink: { 500: "#F26798" }, + red: { 500: "#FF452C" }, + orange: { 500: "#FF9916" }, + yellow: { 500: "#FFD80B" }, + mint: { 500: "#00DCA7" }, + green: { 500: "#00A651" }, + }, + }, + }, +}); export default createSystem(defaultConfig, config); diff --git a/yarn.lock b/yarn.lock index 83aa58e..8795593 100644 --- a/yarn.lock +++ b/yarn.lock @@ -550,6 +550,11 @@ resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz" integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== +"@fontsource/ibm-plex-sans@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@fontsource/ibm-plex-sans/-/ibm-plex-sans-5.1.0.tgz#9cd6bcce9817c55565ae2cf92629ce9a9f617a6b" + integrity sha512-v2aFHGh33ogG+At6dVNUCX6vWlNAhQ6STWj5WrBKPxVWX1SsAnHNq8sXQBa7WHEt29Irmozuk7GTp6GzFlpwdQ== + "@humanfs/core@^0.19.1": version "0.19.1" resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz" @@ -3942,7 +3947,7 @@ react-dom@^18.3.1: react-icons@^5.4.0: version "5.4.0" - resolved "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.4.0.tgz#443000f6e5123ee1b21ea8c0a716f6e7797f7416" integrity sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ== react-is@^16.13.1, react-is@^16.7.0: