From 4b1084fd0a622f1170c62d40f17afb4c62c00c61 Mon Sep 17 00:00:00 2001 From: Scott Thompson <145565743+scotttjob@users.noreply.github.com> Date: Wed, 29 Jan 2025 07:43:19 -0400 Subject: [PATCH 01/28] initial integration --- packages/site/src/layout/Layout.tsx | 70 ++++++++++++++++++- packages/site/src/layout/NavMenu.module.css | 40 ----------- packages/site/src/layout/NavMenu.tsx | 23 +----- .../site/src/layout/SearchButton.module.css | 40 +++++++++++ packages/site/src/layout/SearchButton.tsx | 28 ++++++++ 5 files changed, 138 insertions(+), 63 deletions(-) create mode 100644 packages/site/src/layout/SearchButton.module.css create mode 100644 packages/site/src/layout/SearchButton.tsx diff --git a/packages/site/src/layout/Layout.tsx b/packages/site/src/layout/Layout.tsx index 2665394353..4dfec34534 100644 --- a/packages/site/src/layout/Layout.tsx +++ b/packages/site/src/layout/Layout.tsx @@ -1,6 +1,15 @@ -import { PropsWithChildren, useEffect, useRef } from "react"; +import { PropsWithChildren, useEffect, useRef, useState } from "react"; import { Route, Switch, useHistory, useLocation } from "react-router"; +import { + Box, + Button, + Content, + InputText, + SideDrawer, + Text, +} from "@jobber/components"; import { NavMenu } from "./NavMenu"; +import { SearchButton } from "./SearchButton"; import { routes } from "../routes"; import "./code-theme.css"; import { ToggleThemeButton } from "../components/ToggleThemeButton"; @@ -13,12 +22,14 @@ import { FeedbackBanner } from "../components/FeedbackBanner"; * @returns ReactNode */ +// eslint-disable-next-line max-statements export const Layout = () => { const location = useLocation(); const scrollPane = useRef(null); const path = new URLSearchParams(location.search).get("path"); const history = useHistory(); - + const [tritonOpen, setTritonOpen] = useState(false); + const [question, setQuestion] = useState(""); useEffect(() => { if (scrollPane?.current) { scrollPane?.current.scrollTo({ top: 0 }); @@ -37,6 +48,29 @@ export const Layout = () => { } } + const openTriton = () => { + setTritonOpen(true); + }; + + const sendSearch = async () => { + console.log("searching!", question); + const b = await fetch("http://localhost:8788/stream", { + headers: { + "Content-Type": "application/json", + "Triton-Api-Key": localStorage.getItem("tritonApiKey") || "", + }, + method: "POST", + body: JSON.stringify({ + personality: "developer", + query: question, + questions: [], + questionType: "web", + responses: [], + }), + }); + console.log("HI!", await b.json()); + }; + return ( @@ -50,11 +84,43 @@ export const Layout = () => { ref={scrollPane} tabIndex={0} > +
+ + + + +
+ + setTritonOpen(false)}> + + + + Welcome to Triton! + + + setQuestion(d as string)} + /> + + +
); }; diff --git a/packages/site/src/layout/NavMenu.module.css b/packages/site/src/layout/NavMenu.module.css index cce7c45eea..af09c0f153 100644 --- a/packages/site/src/layout/NavMenu.module.css +++ b/packages/site/src/layout/NavMenu.module.css @@ -50,46 +50,6 @@ border-radius: var(--radius-small); } -.searchButton { - display: flex; - align-items: center; - border: var(--border-base) solid var(--color-border--interactive); - border-radius: var(--radius-base); - padding: var(--space-small); - background: var(--color-surface); - outline: transparent; - cursor: pointer; - transition: all var(--timing-base) ease-out; - - &:focus-visible { - box-shadow: var(--shadow-focus); - background-color: var(--color-surface--background--hover); - } -} - -.searchButton:hover { - background: var(--color-surface--background--hover); - border: var(--border-base) solid var(--color-interactive--subtle--hover); -} - -.searchButtonText { - margin: 0 var(--space-small); - flex: 1; - text-align: start; -} - -.searchKeyIndicator { - background: var(--color-surface--background); - width: 20px; - height: 20px; - font-size: var(--typography--fontSize-large); - color: var(--color-text); - display: flex; - align-items: center; - justify-content: center; - border-radius: var(--radius-small); - box-shadow: var(--shadow-low); -} .navMenuLink { color: var(--color-text); diff --git a/packages/site/src/layout/NavMenu.tsx b/packages/site/src/layout/NavMenu.tsx index f1dff83844..e5be230793 100644 --- a/packages/site/src/layout/NavMenu.tsx +++ b/packages/site/src/layout/NavMenu.tsx @@ -1,7 +1,6 @@ -import { Box, Button, Icon, Typography } from "@jobber/components"; +import { Box, Button, Typography } from "@jobber/components"; import { Link, useLocation } from "react-router-dom"; -import { Fragment, PropsWithChildren, useRef, useState } from "react"; -import { SearchBox } from "./SearchBox"; +import { Fragment, PropsWithChildren, useRef } from "react"; import AnimatedPresenceDisclosure from "./AnimatedPresenceDisclosure"; import styles from "./NavMenu.module.css"; import { routes } from "../routes"; @@ -18,7 +17,6 @@ interface NavMenuProps { * @returns ReactNode */ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { - const [open, setOpen] = useState(false); const { isMinimal } = useAtlantisSite(); const { pathname } = useLocation(); const selectedRef = useRef(null); @@ -82,23 +80,6 @@ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { - - - -
diff --git a/packages/site/src/layout/SearchButton.module.css b/packages/site/src/layout/SearchButton.module.css new file mode 100644 index 0000000000..469f20ae5e --- /dev/null +++ b/packages/site/src/layout/SearchButton.module.css @@ -0,0 +1,40 @@ +.searchButton { + display: flex; + align-items: center; + border: var(--border-base) solid var(--color-border--interactive); + border-radius: var(--radius-base); + padding: var(--space-small); + background: var(--color-surface); + outline: transparent; + cursor: pointer; + transition: all var(--timing-base) ease-out; + + &:focus-visible { + box-shadow: var(--shadow-focus); + background-color: var(--color-surface--background--hover); + } +} + +.searchButton:hover { + background: var(--color-surface--background--hover); + border: var(--border-base) solid var(--color-interactive--subtle--hover); +} + +.searchButtonText { + margin: 0 var(--space-small); + flex: 1; + text-align: start; +} + +.searchKeyIndicator { + background: var(--color-surface--background); + width: 20px; + height: 20px; + font-size: var(--typography--fontSize-large); + color: var(--color-text); + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--radius-small); + box-shadow: var(--shadow-low); +} \ No newline at end of file diff --git a/packages/site/src/layout/SearchButton.tsx b/packages/site/src/layout/SearchButton.tsx new file mode 100644 index 0000000000..2f834e4b1c --- /dev/null +++ b/packages/site/src/layout/SearchButton.tsx @@ -0,0 +1,28 @@ +import { Box, Icon, Typography } from "@jobber/components"; +import { useState } from "react"; +import { SearchBox } from "./SearchBox"; +import styles from "./SearchButton.module.css"; + +export const SearchButton = () => { + const [open, setOpen] = useState(false); + + return ( + + + + + ); +}; From bb6e64f87241ddf5f6a2aa9c1076cb9934193868 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Wed, 12 Feb 2025 10:58:18 -0800 Subject: [PATCH 02/28] docs: Create top nav (#2364) * create header component * accurate header width calculation * ToggleThemeButton into Header * align ToggleThemeButton to the right of the header * make sure nav menu aligns with header * border on the header * Header takes up the whole width * make sure only BaseView.Main scrolls with header on top * move top nav to be inside BaseView.Main * refactor Triton SideDrawer into its own component and created TritonContext * header styling * dont use box as main due to lack of boxShadow * make header responsive in minimal mode * fix eslint * overflow auto on main routed div * ask triton button styling * only rounded top corners of main content * fixed main content not growing * fix BaseView border radius * some layout/styling tweaks * add header to collection pages and make scrollbar inside the content * isolate blending to only content card wrapper * align nav with header * Renamed Header to TopNav * use Box instead of div --------- Co-authored-by: Chris Murray <39704901+chris-at-jobber@users.noreply.github.com> --- packages/site/src/components/PageBlock.tsx | 93 +++++++++++-------- .../site/src/components/ToggleThemeButton.tsx | 23 +---- .../site/src/components/TritonSideDrawer.tsx | 32 +++++++ packages/site/src/layout/BaseView.tsx | 46 +++++---- packages/site/src/layout/Layout.tsx | 74 +-------------- packages/site/src/layout/NavMenu.module.css | 2 +- packages/site/src/layout/PageWrapper.tsx | 6 +- packages/site/src/layout/TopNav.tsx | 33 +++++++ packages/site/src/main.css | 1 + packages/site/src/main.tsx | 5 +- .../site/src/providers/TritonProvider.tsx | 60 ++++++++++++ 11 files changed, 226 insertions(+), 149 deletions(-) create mode 100644 packages/site/src/components/TritonSideDrawer.tsx create mode 100644 packages/site/src/layout/TopNav.tsx create mode 100644 packages/site/src/providers/TritonProvider.tsx diff --git a/packages/site/src/components/PageBlock.tsx b/packages/site/src/components/PageBlock.tsx index 634cd6048a..94ae67f15c 100644 --- a/packages/site/src/components/PageBlock.tsx +++ b/packages/site/src/components/PageBlock.tsx @@ -8,6 +8,7 @@ import { CategoryCardSection } from "./CategoryCardSection"; import { PageWrapper } from "../layout/PageWrapper"; import { ContentCardProps } from "../types/components"; import usePageTitle from "../hooks/usePageTitle"; +import { TopNav } from "../layout/TopNav"; interface PageBlockProps { readonly structure: { @@ -63,48 +64,62 @@ export const PageBlock = ({ structure }: PageBlockProps) => { return ( - - - {structure.showSegmentedControl && ( -
- - - Categorical - - - Alphabetical - - -
- )} + +
+
+ + + {structure.showSegmentedControl && ( +
+ + + Categorical + + + Alphabetical + + +
+ )} - {structure.useCategories && cardView === "category" ? ( - <> - {sectionedComponents().map(({ section, items }) => ( - - {items.map((content, index) => ( + {structure.useCategories && cardView === "category" ? ( + <> + {sectionedComponents().map(({ section, items }) => ( + + {items.map((content, index) => ( + + ))} + + ))} + + ) : ( + + {structure.body.content.map((content, index) => ( ))} - - ))} - - ) : ( - - {structure.body.content.map((content, index) => ( - - ))} - - )} -
+ + )} + +
+
); }; diff --git a/packages/site/src/components/ToggleThemeButton.tsx b/packages/site/src/components/ToggleThemeButton.tsx index 889058cc31..da635a2a18 100644 --- a/packages/site/src/components/ToggleThemeButton.tsx +++ b/packages/site/src/components/ToggleThemeButton.tsx @@ -17,23 +17,10 @@ export const ToggleThemeButton = () => { }; return ( -
-
+ + + + ); +} diff --git a/packages/site/src/layout/BaseView.tsx b/packages/site/src/layout/BaseView.tsx index d3958ed6ce..3a9b7dfd85 100644 --- a/packages/site/src/layout/BaseView.tsx +++ b/packages/site/src/layout/BaseView.tsx @@ -1,5 +1,6 @@ import { Box } from "@jobber/components"; import { PropsWithChildren } from "react"; +import { TopNav } from "./TopNav"; export function BaseView({ children }: PropsWithChildren) { return
{children}
; @@ -11,27 +12,40 @@ BaseView.Main = function Main({ readonly children: React.ReactNode; }) { return ( -
- + + +
- {children} + +
+ {children} +
+
- -
+
+ ); }; diff --git a/packages/site/src/layout/Layout.tsx b/packages/site/src/layout/Layout.tsx index 762648ec64..18a030c770 100644 --- a/packages/site/src/layout/Layout.tsx +++ b/packages/site/src/layout/Layout.tsx @@ -1,34 +1,22 @@ -import { PropsWithChildren, useEffect, useRef, useState } from "react"; +import { PropsWithChildren, useEffect, useRef } from "react"; import { Route, Switch, useHistory, useLocation } from "react-router"; -import { - Box, - Button, - Content, - InputText, - SideDrawer, - Text, -} from "@jobber/components"; import { NavMenu } from "./NavMenu"; -import { SearchButton } from "./SearchButton"; import { routes } from "../routes"; import "./code-theme.css"; -import { ToggleThemeButton } from "../components/ToggleThemeButton"; import { hooksList } from "../hooksList"; import { NotFoundPage } from "../pages/NotFoundPage"; +import { TritonSideDrawer } from "../components/TritonSideDrawer"; /** * Layout for whole application. This will display the NavMenu and the content of the page. * @returns ReactNode */ -// eslint-disable-next-line max-statements export const Layout = () => { const location = useLocation(); const scrollPane = useRef(null); const path = new URLSearchParams(location.search).get("path"); const history = useHistory(); - const [tritonOpen, setTritonOpen] = useState(false); - const [question, setQuestion] = useState(""); useEffect(() => { if (scrollPane?.current) { scrollPane?.current.scrollTo({ top: 0 }); @@ -47,29 +35,6 @@ export const Layout = () => { } } - const openTriton = () => { - setTritonOpen(true); - }; - - const sendSearch = async () => { - console.log("searching!", question); - const b = await fetch("http://localhost:8788/stream", { - headers: { - "Content-Type": "application/json", - "Triton-Api-Key": localStorage.getItem("tritonApiKey") || "", - }, - method: "POST", - body: JSON.stringify({ - personality: "developer", - query: question, - questions: [], - questionType: "web", - responses: [], - }), - }); - console.log("HI!", await b.json()); - }; - return ( @@ -83,42 +48,9 @@ export const Layout = () => { ref={scrollPane} tabIndex={0} > -
- - - - -
- - - - setTritonOpen(false)}> - - - - Welcome to Triton! - - - setQuestion(d as string)} - /> - - - + ); }; diff --git a/packages/site/src/layout/NavMenu.module.css b/packages/site/src/layout/NavMenu.module.css index f35a5a63f7..faeef746d3 100644 --- a/packages/site/src/layout/NavMenu.module.css +++ b/packages/site/src/layout/NavMenu.module.css @@ -5,7 +5,7 @@ --navItemHeight: 40px; display: flex; flex-direction: column; - padding: 36px 0 0 0; + padding: 35px 0 0 0; height: 100dvh; min-width: var(--sideBarWidth); box-sizing: border-box; diff --git a/packages/site/src/layout/PageWrapper.tsx b/packages/site/src/layout/PageWrapper.tsx index 7d3fe33f5e..b1def72dbb 100644 --- a/packages/site/src/layout/PageWrapper.tsx +++ b/packages/site/src/layout/PageWrapper.tsx @@ -9,9 +9,9 @@ export const PageWrapper = ({ children }: PropsWithChildren) => { return (
{children} diff --git a/packages/site/src/layout/TopNav.tsx b/packages/site/src/layout/TopNav.tsx new file mode 100644 index 0000000000..6743027b1b --- /dev/null +++ b/packages/site/src/layout/TopNav.tsx @@ -0,0 +1,33 @@ +import { Box, Button, Tooltip } from "@jobber/components"; +import { SearchButton } from "./SearchButton"; +import { ToggleThemeButton } from "../components/ToggleThemeButton"; +import { useTritonChat } from "../providers/TritonProvider"; + +export const TopNav = () => { + const { onOpenTriton } = useTritonChat(); + + return ( + + + + + + +
From 0f7dfb4007339f95a7e7857a8bc5a4540f7b4702 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Fri, 14 Feb 2025 11:04:33 -0800 Subject: [PATCH 05/28] style layout and search button in small viewport --- .../site/src/layout/SearchButton.module.css | 61 +++++++++++-------- packages/site/src/layout/TopNav.tsx | 43 ++++++++----- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/packages/site/src/layout/SearchButton.module.css b/packages/site/src/layout/SearchButton.module.css index 469f20ae5e..f1ae03f5f5 100644 --- a/packages/site/src/layout/SearchButton.module.css +++ b/packages/site/src/layout/SearchButton.module.css @@ -1,40 +1,47 @@ .searchButton { - display: flex; - align-items: center; - border: var(--border-base) solid var(--color-border--interactive); - border-radius: var(--radius-base); - padding: var(--space-small); - background: var(--color-surface); - outline: transparent; - cursor: pointer; - transition: all var(--timing-base) ease-out; + display: flex; + align-items: center; + border: var(--border-base) solid var(--color-border--interactive); + border-radius: var(--radius-base); + padding: var(--space-small); + background: var(--color-surface); + outline: transparent; + cursor: pointer; + transition: all var(--timing-base) ease-out; - &:focus-visible { - box-shadow: var(--shadow-focus); - background-color: var(--color-surface--background--hover); - } + &:focus-visible { + box-shadow: var(--shadow-focus); + background-color: var(--color-surface--background--hover); + } } .searchButton:hover { - background: var(--color-surface--background--hover); - border: var(--border-base) solid var(--color-interactive--subtle--hover); + background: var(--color-surface--background--hover); + border: var(--border-base) solid var(--color-interactive--subtle--hover); } .searchButtonText { - margin: 0 var(--space-small); - flex: 1; - text-align: start; + margin: 0 var(--space-small); + display: none; + flex: 1; + text-align: start; + @media screen and (min-width: 768px) { + display: block; + } } .searchKeyIndicator { - background: var(--color-surface--background); - width: 20px; - height: 20px; - font-size: var(--typography--fontSize-large); - color: var(--color-text); + background: var(--color-surface--background); + width: 20px; + height: 20px; + font-size: var(--typography--fontSize-large); + color: var(--color-text); + display: none; + align-items: center; + justify-content: center; + border-radius: var(--radius-small); + box-shadow: var(--shadow-low); + @media screen and (min-width: 768px) { display: flex; - align-items: center; - justify-content: center; - border-radius: var(--radius-small); - box-shadow: var(--shadow-low); + } } \ No newline at end of file diff --git a/packages/site/src/layout/TopNav.tsx b/packages/site/src/layout/TopNav.tsx index f4fbdeede4..439477d90e 100644 --- a/packages/site/src/layout/TopNav.tsx +++ b/packages/site/src/layout/TopNav.tsx @@ -12,7 +12,13 @@ export const TopNav = () => { const { mediumAndUp } = useBreakpoints(); return ( - +
{ - - + + + + + +
+
{children}
+ + + ); +} From 6a0e4768fe1ad91e0c009202907b27271347bb6b Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Tue, 18 Feb 2025 15:23:05 -0800 Subject: [PATCH 08/28] move mobile menu open state into atlantis site context --- packages/site/src/layout/Layout.tsx | 5 +++++ packages/site/src/layout/LeftDrawer.module.css | 7 +++++++ packages/site/src/layout/TopNav.tsx | 4 +++- packages/site/src/providers/AtlantisSiteProvider.tsx | 11 +++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/site/src/layout/Layout.tsx b/packages/site/src/layout/Layout.tsx index 18a030c770..71c9af1b9e 100644 --- a/packages/site/src/layout/Layout.tsx +++ b/packages/site/src/layout/Layout.tsx @@ -1,11 +1,13 @@ import { PropsWithChildren, useEffect, useRef } from "react"; import { Route, Switch, useHistory, useLocation } from "react-router"; import { NavMenu } from "./NavMenu"; +import { LeftDrawer } from "./LeftDrawer"; import { routes } from "../routes"; import "./code-theme.css"; import { hooksList } from "../hooksList"; import { NotFoundPage } from "../pages/NotFoundPage"; import { TritonSideDrawer } from "../components/TritonSideDrawer"; +import { useAtlantisSite } from "../providers/AtlantisSiteProvider"; /** * Layout for whole application. This will display the NavMenu and the content of the page. @@ -17,6 +19,8 @@ export const Layout = () => { const scrollPane = useRef(null); const path = new URLSearchParams(location.search).get("path"); const history = useHistory(); + const { isMobileMenuOpen, toggleMobileMenu } = useAtlantisSite(); + useEffect(() => { if (scrollPane?.current) { scrollPane?.current.scrollTo({ top: 0 }); @@ -38,6 +42,7 @@ export const Layout = () => { return ( +
{ const { onOpenTriton } = useTritonChat(); const { mediumAndUp } = useBreakpoints(); + const { toggleMobileMenu } = useAtlantisSite(); return ( { type="tertiary" variation="subtle" size="base" - onClick={() => alert("open menu")} + onClick={toggleMobileMenu} icon="menu" /> diff --git a/packages/site/src/providers/AtlantisSiteProvider.tsx b/packages/site/src/providers/AtlantisSiteProvider.tsx index 2c9dc4bc23..92330fbdce 100644 --- a/packages/site/src/providers/AtlantisSiteProvider.tsx +++ b/packages/site/src/providers/AtlantisSiteProvider.tsx @@ -14,6 +14,8 @@ const AtlantisSiteContext = createContext<{ enableMinimal: () => void; disableMinimal: () => void; isMinimal: boolean; + isMobileMenuOpen: boolean; + toggleMobileMenu: () => void; }>({ minimal: { requested: false, @@ -22,6 +24,8 @@ const AtlantisSiteContext = createContext<{ isMinimal: false, enableMinimal: () => ({}), disableMinimal: () => ({}), + isMobileMenuOpen: false, + toggleMobileMenu: () => ({}), }); export const useAtlantisSite = () => { @@ -35,6 +39,11 @@ export const AtlantisSiteProvider = ({ readonly minimal: { enabled: boolean; requested: boolean }; }>) => { const [minimalState, setMinimalState] = useState(minimal); + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + + const toggleMobileMenu = useCallback(() => { + setIsMobileMenuOpen(prevState => !prevState); + }, []); const enableMinimal = useCallback(() => { setMinimalState(prevState => ({ @@ -57,6 +66,8 @@ export const AtlantisSiteProvider = ({ isMinimal: minimalState.enabled && minimalState.requested, enableMinimal, disableMinimal, + isMobileMenuOpen, + toggleMobileMenu, }} > {children} From 7261c51ba09dfb58dc3881905842cb6be07b1c90 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Tue, 18 Feb 2025 15:49:46 -0800 Subject: [PATCH 09/28] Layout host separate mobile and desktop nav menu --- packages/site/src/layout/DesktopNavMenu.module.css | 7 +++++++ packages/site/src/layout/DesktopNavMenu.tsx | 10 ++++++++++ packages/site/src/layout/Layout.tsx | 10 ++++++---- packages/site/src/layout/MobileNavMenu.module.css | 7 +++++++ packages/site/src/layout/MobileNavMenu.tsx | 10 ++++++++++ packages/site/src/layout/NavMenu.module.css | 6 +----- packages/site/src/layout/NavMenu.tsx | 2 +- 7 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 packages/site/src/layout/DesktopNavMenu.module.css create mode 100644 packages/site/src/layout/DesktopNavMenu.tsx create mode 100644 packages/site/src/layout/MobileNavMenu.module.css create mode 100644 packages/site/src/layout/MobileNavMenu.tsx diff --git a/packages/site/src/layout/DesktopNavMenu.module.css b/packages/site/src/layout/DesktopNavMenu.module.css new file mode 100644 index 0000000000..76e590cc79 --- /dev/null +++ b/packages/site/src/layout/DesktopNavMenu.module.css @@ -0,0 +1,7 @@ +.desktopNavMenu { + display: none; + + @media screen and (min-width: 768px) { + display: block; + } +} \ No newline at end of file diff --git a/packages/site/src/layout/DesktopNavMenu.tsx b/packages/site/src/layout/DesktopNavMenu.tsx new file mode 100644 index 0000000000..4e7992d37d --- /dev/null +++ b/packages/site/src/layout/DesktopNavMenu.tsx @@ -0,0 +1,10 @@ +import { NavMenu, NavMenuProps } from "./NavMenu"; +import styles from "./DesktopNavMenu.module.css"; + +export const DesktopNavMenu = ({ mainContentRef }: NavMenuProps) => { + return ( +
+ +
+ ); +}; diff --git a/packages/site/src/layout/Layout.tsx b/packages/site/src/layout/Layout.tsx index 71c9af1b9e..bd749186b2 100644 --- a/packages/site/src/layout/Layout.tsx +++ b/packages/site/src/layout/Layout.tsx @@ -1,14 +1,14 @@ import { PropsWithChildren, useEffect, useRef } from "react"; import { Route, Switch, useHistory, useLocation } from "react-router"; -import { NavMenu } from "./NavMenu"; +import { MobileNavMenu } from "./MobileNavMenu"; import { LeftDrawer } from "./LeftDrawer"; +import { DesktopNavMenu } from "./DesktopNavMenu"; import { routes } from "../routes"; import "./code-theme.css"; import { hooksList } from "../hooksList"; import { NotFoundPage } from "../pages/NotFoundPage"; import { TritonSideDrawer } from "../components/TritonSideDrawer"; import { useAtlantisSite } from "../providers/AtlantisSiteProvider"; - /** * Layout for whole application. This will display the NavMenu and the content of the page. * @returns ReactNode @@ -41,8 +41,10 @@ export const Layout = () => { return ( - - + + + +
{ + return ( +
+ +
+ ); +}; diff --git a/packages/site/src/layout/NavMenu.module.css b/packages/site/src/layout/NavMenu.module.css index 587a9c4a42..faeef746d3 100644 --- a/packages/site/src/layout/NavMenu.module.css +++ b/packages/site/src/layout/NavMenu.module.css @@ -3,16 +3,12 @@ --negativeHoverOffset: calc(-1 * var(--hoverOffset)); --subItemInset: calc(var(--space-small) + var(--space-smaller)); --navItemHeight: 40px; - display: none; + display: flex; flex-direction: column; padding: 35px 0 0 0; height: 100dvh; min-width: var(--sideBarWidth); box-sizing: border-box; - - @media screen and (min-width: 768px) { - display: flex; - } } .navMenuContainer>* { diff --git a/packages/site/src/layout/NavMenu.tsx b/packages/site/src/layout/NavMenu.tsx index 45581c95ac..d0f4db2408 100644 --- a/packages/site/src/layout/NavMenu.tsx +++ b/packages/site/src/layout/NavMenu.tsx @@ -8,7 +8,7 @@ import { JobberLogo } from "../assets/JobberLogo.svg"; import { useAtlantisSite } from "../providers/AtlantisSiteProvider"; import { VisibleWhenFocused } from "../components/VisibleWhenFocused"; -interface NavMenuProps { +export interface NavMenuProps { readonly mainContentRef: React.RefObject; } From 495acc4962bcb54411c2a0603e979f8aa3626a04 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Tue, 18 Feb 2025 15:58:18 -0800 Subject: [PATCH 10/28] keep responsive menu display inside single NavMenu component --- .../site/src/layout/DesktopNavMenu.module.css | 7 ------- packages/site/src/layout/DesktopNavMenu.tsx | 10 ---------- packages/site/src/layout/Layout.tsx | 11 ++--------- .../site/src/layout/MobileNavMenu.module.css | 7 ------- packages/site/src/layout/MobileNavMenu.tsx | 10 ---------- packages/site/src/layout/NavMenu.module.css | 16 ++++++++++++++++ packages/site/src/layout/NavMenu.tsx | 16 ++++++++++++++-- 7 files changed, 32 insertions(+), 45 deletions(-) delete mode 100644 packages/site/src/layout/DesktopNavMenu.module.css delete mode 100644 packages/site/src/layout/DesktopNavMenu.tsx delete mode 100644 packages/site/src/layout/MobileNavMenu.module.css delete mode 100644 packages/site/src/layout/MobileNavMenu.tsx diff --git a/packages/site/src/layout/DesktopNavMenu.module.css b/packages/site/src/layout/DesktopNavMenu.module.css deleted file mode 100644 index 76e590cc79..0000000000 --- a/packages/site/src/layout/DesktopNavMenu.module.css +++ /dev/null @@ -1,7 +0,0 @@ -.desktopNavMenu { - display: none; - - @media screen and (min-width: 768px) { - display: block; - } -} \ No newline at end of file diff --git a/packages/site/src/layout/DesktopNavMenu.tsx b/packages/site/src/layout/DesktopNavMenu.tsx deleted file mode 100644 index 4e7992d37d..0000000000 --- a/packages/site/src/layout/DesktopNavMenu.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { NavMenu, NavMenuProps } from "./NavMenu"; -import styles from "./DesktopNavMenu.module.css"; - -export const DesktopNavMenu = ({ mainContentRef }: NavMenuProps) => { - return ( -
- -
- ); -}; diff --git a/packages/site/src/layout/Layout.tsx b/packages/site/src/layout/Layout.tsx index bd749186b2..da027cea80 100644 --- a/packages/site/src/layout/Layout.tsx +++ b/packages/site/src/layout/Layout.tsx @@ -1,14 +1,11 @@ import { PropsWithChildren, useEffect, useRef } from "react"; import { Route, Switch, useHistory, useLocation } from "react-router"; -import { MobileNavMenu } from "./MobileNavMenu"; -import { LeftDrawer } from "./LeftDrawer"; -import { DesktopNavMenu } from "./DesktopNavMenu"; +import { NavMenu } from "./NavMenu"; import { routes } from "../routes"; import "./code-theme.css"; import { hooksList } from "../hooksList"; import { NotFoundPage } from "../pages/NotFoundPage"; import { TritonSideDrawer } from "../components/TritonSideDrawer"; -import { useAtlantisSite } from "../providers/AtlantisSiteProvider"; /** * Layout for whole application. This will display the NavMenu and the content of the page. * @returns ReactNode @@ -19,7 +16,6 @@ export const Layout = () => { const scrollPane = useRef(null); const path = new URLSearchParams(location.search).get("path"); const history = useHistory(); - const { isMobileMenuOpen, toggleMobileMenu } = useAtlantisSite(); useEffect(() => { if (scrollPane?.current) { @@ -41,10 +37,7 @@ export const Layout = () => { return ( - - - - +
{ - return ( -
- -
- ); -}; diff --git a/packages/site/src/layout/NavMenu.module.css b/packages/site/src/layout/NavMenu.module.css index faeef746d3..4bdc20ba9e 100644 --- a/packages/site/src/layout/NavMenu.module.css +++ b/packages/site/src/layout/NavMenu.module.css @@ -130,4 +130,20 @@ a.navFooterLink { margin-top: auto; font-size: var(--typography--fontSize-small); color: var(--color-text--secondary); +} + +.desktopNavContainer { + display: none; + + @media screen and (min-width: 768px) { + display: block; + } +} + +.mobileNavContainer { + display: block; + + @media screen and (min-width: 768px) { + display: none; + } } \ No newline at end of file diff --git a/packages/site/src/layout/NavMenu.tsx b/packages/site/src/layout/NavMenu.tsx index d0f4db2408..4baa50e444 100644 --- a/packages/site/src/layout/NavMenu.tsx +++ b/packages/site/src/layout/NavMenu.tsx @@ -3,6 +3,7 @@ import { Link, useLocation } from "react-router-dom"; import { Fragment, PropsWithChildren, useRef } from "react"; import AnimatedPresenceDisclosure from "./AnimatedPresenceDisclosure"; import styles from "./NavMenu.module.css"; +import { LeftDrawer } from "./LeftDrawer"; import { routes } from "../routes"; import { JobberLogo } from "../assets/JobberLogo.svg"; import { useAtlantisSite } from "../providers/AtlantisSiteProvider"; @@ -17,7 +18,7 @@ export interface NavMenuProps { * @returns ReactNode */ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { - const { isMinimal } = useAtlantisSite(); + const { isMinimal, isMobileMenuOpen, toggleMobileMenu } = useAtlantisSite(); const { pathname } = useLocation(); const selectedRef = useRef(null); @@ -69,7 +70,7 @@ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { mainContentRef.current?.focus(); }; - return ( + const menuContent = ( ); + + return ( + <> +
{menuContent}
+
+ + {menuContent} + +
+ + ); }; const getLinkClassName = ( From 981c75c1b23491006cd8d27b7325edc96581a7ca Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Tue, 18 Feb 2025 16:34:21 -0800 Subject: [PATCH 11/28] close mobile nav menu on navigate --- packages/site/src/layout/NavMenu.tsx | 10 ++++++++-- .../site/src/providers/AtlantisSiteProvider.tsx | 15 +++++++++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/site/src/layout/NavMenu.tsx b/packages/site/src/layout/NavMenu.tsx index 4baa50e444..3c07c456b9 100644 --- a/packages/site/src/layout/NavMenu.tsx +++ b/packages/site/src/layout/NavMenu.tsx @@ -18,7 +18,8 @@ export interface NavMenuProps { * @returns ReactNode */ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { - const { isMinimal, isMobileMenuOpen, toggleMobileMenu } = useAtlantisSite(); + const { isMinimal, isMobileMenuOpen, toggleMobileMenu, closeMobileMenu } = + useAtlantisSite(); const { pathname } = useLocation(); const selectedRef = useRef(null); @@ -68,6 +69,7 @@ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { const skipToContent = () => { mainContentRef.current?.focus(); + closeMobileMenu(); }; const menuContent = ( @@ -77,7 +79,7 @@ export const NavMenu = ({ mainContentRef }: NavMenuProps) => {
+ {header} +
{children}
diff --git a/packages/site/src/layout/NavMenu.module.css b/packages/site/src/layout/NavMenu.module.css index 4bdc20ba9e..5c7f8a2c6b 100644 --- a/packages/site/src/layout/NavMenu.module.css +++ b/packages/site/src/layout/NavMenu.module.css @@ -5,10 +5,13 @@ --navItemHeight: 40px; display: flex; flex-direction: column; - padding: 35px 0 0 0; height: 100dvh; min-width: var(--sideBarWidth); box-sizing: border-box; + + @media screen and (min-width: 768px) { + padding: 35px 0 0 0; + } } .navMenuContainer>* { @@ -146,4 +149,12 @@ a.navFooterLink { @media screen and (min-width: 768px) { display: none; } +} + +.navMenuHeaderLogo { + display: none; + + @media screen and (min-width: 768px) { + display: block; + } } \ No newline at end of file diff --git a/packages/site/src/layout/NavMenu.tsx b/packages/site/src/layout/NavMenu.tsx index 3c07c456b9..637f1960a4 100644 --- a/packages/site/src/layout/NavMenu.tsx +++ b/packages/site/src/layout/NavMenu.tsx @@ -78,11 +78,11 @@ export const NavMenu = ({ mainContentRef }: NavMenuProps) => {
@@ -126,7 +126,17 @@ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { <>
{menuContent}
- + + + + + + } + > {menuContent}
From c6967bd3db609e1a84521eec990b91daf5ee4339 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Thu, 20 Feb 2025 12:23:56 -0800 Subject: [PATCH 15/28] fixed view in storybook link not showing up in mobile viewport --- packages/site/src/layout/NavMenu.module.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/site/src/layout/NavMenu.module.css b/packages/site/src/layout/NavMenu.module.css index 5c7f8a2c6b..e9ee9d1195 100644 --- a/packages/site/src/layout/NavMenu.module.css +++ b/packages/site/src/layout/NavMenu.module.css @@ -5,12 +5,13 @@ --navItemHeight: 40px; display: flex; flex-direction: column; - height: 100dvh; + height: 100%; min-width: var(--sideBarWidth); box-sizing: border-box; @media screen and (min-width: 768px) { padding: 35px 0 0 0; + height: 100dvh; } } From f4f7154982cb8a1024c30f8e3589226f38ea6560 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Thu, 20 Feb 2025 12:39:34 -0800 Subject: [PATCH 16/28] cleanup --- packages/site/src/layout/Layout.tsx | 2 +- .../site/src/layout/LeftDrawer.module.css | 82 +++++++++---------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/packages/site/src/layout/Layout.tsx b/packages/site/src/layout/Layout.tsx index da027cea80..18a030c770 100644 --- a/packages/site/src/layout/Layout.tsx +++ b/packages/site/src/layout/Layout.tsx @@ -6,6 +6,7 @@ import "./code-theme.css"; import { hooksList } from "../hooksList"; import { NotFoundPage } from "../pages/NotFoundPage"; import { TritonSideDrawer } from "../components/TritonSideDrawer"; + /** * Layout for whole application. This will display the NavMenu and the content of the page. * @returns ReactNode @@ -16,7 +17,6 @@ export const Layout = () => { const scrollPane = useRef(null); const path = new URLSearchParams(location.search).get("path"); const history = useHistory(); - useEffect(() => { if (scrollPane?.current) { scrollPane?.current.scrollTo({ top: 0 }); diff --git a/packages/site/src/layout/LeftDrawer.module.css b/packages/site/src/layout/LeftDrawer.module.css index 9af8bd8d8f..b02f230f60 100644 --- a/packages/site/src/layout/LeftDrawer.module.css +++ b/packages/site/src/layout/LeftDrawer.module.css @@ -1,47 +1,47 @@ .overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(var(--color-black--rgb), 0.4); - z-index: var(--elevation-modal); - } - + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(var(--color-black--rgb), 0.4); + z-index: var(--elevation-modal); +} + +.drawer { + position: fixed; + top: 0; + left: 0; + height: 100%; + width: 100%; + background: var(--color-surface--background); + z-index: var(--elevation-modal); + display: flex; + flex-direction: column; + animation: slideIn 200ms ease-out; +} + +@media screen and (min-width: 768px) { + .overlay, .drawer { - position: fixed; - top: 0; - left: 0; - height: 100%; - width: 100%; - background: var(--color-surface--background); - z-index: var(--elevation-modal); - display: flex; - flex-direction: column; - animation: slideIn 200ms ease-out; + display: none; } +} - @media screen and (min-width: 768px) { - .overlay, - .drawer { - display: none; - } - } - - .header { - padding: var(--space-base); +.header { + padding: var(--space-base); +} + +.content { + flex: 1; + overflow-y: hidden; +} + +@keyframes slideIn { + from { + transform: translateX(-100%); } - - .content { - flex: 1; - overflow-y: hidden; + to { + transform: translateX(0); } - - @keyframes slideIn { - from { - transform: translateX(-100%); - } - to { - transform: translateX(0); - } - } \ No newline at end of file +} \ No newline at end of file From ee518679c95b7d81b50211a63bb017a6062868ac Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Thu, 20 Feb 2025 14:02:38 -0800 Subject: [PATCH 17/28] consolidate mobile menu state handler by removing closeMobileMenu --- .../src/layout/AnimatedPresenceDisclosure.tsx | 4 ++-- packages/site/src/layout/NavMenu.tsx | 17 ++++++++--------- .../site/src/providers/AtlantisSiteProvider.tsx | 7 ------- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/packages/site/src/layout/AnimatedPresenceDisclosure.tsx b/packages/site/src/layout/AnimatedPresenceDisclosure.tsx index e50c4e9c8f..1640567b53 100644 --- a/packages/site/src/layout/AnimatedPresenceDisclosure.tsx +++ b/packages/site/src/layout/AnimatedPresenceDisclosure.tsx @@ -24,7 +24,7 @@ function AnimatedPresenceDisclosure({ [children], ); - const { closeMobileMenu } = useAtlantisSite(); + const { toggleMobileMenu } = useAtlantisSite(); // Determine if any child is selected based on the current URL const hasSelectedChild = childrenArray.some( @@ -66,7 +66,7 @@ function AnimatedPresenceDisclosure({ isTitleSelected ? styles.selected : "" } stickySectionHeader`} > - + {title} diff --git a/packages/site/src/layout/NavMenu.tsx b/packages/site/src/layout/NavMenu.tsx index 637f1960a4..ba6e32a3df 100644 --- a/packages/site/src/layout/NavMenu.tsx +++ b/packages/site/src/layout/NavMenu.tsx @@ -18,8 +18,7 @@ export interface NavMenuProps { * @returns ReactNode */ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { - const { isMinimal, isMobileMenuOpen, toggleMobileMenu, closeMobileMenu } = - useAtlantisSite(); + const { isMinimal, isMobileMenuOpen, toggleMobileMenu } = useAtlantisSite(); const { pathname } = useLocation(); const selectedRef = useRef(null); @@ -69,7 +68,7 @@ export const NavMenu = ({ mainContentRef }: NavMenuProps) => { const skipToContent = () => { mainContentRef.current?.focus(); - closeMobileMenu(); + toggleMobileMenu(); }; const menuContent = ( @@ -79,7 +78,7 @@ export const NavMenu = ({ mainContentRef }: NavMenuProps) => {
+ } /> - + + + ); +}; + +export function TritonSideDrawer() { + const { + tritonOpen, + onCloseTriton, + question, + setQuestion, + sendSearch, + setApiKey, + loading, + validateApiKey, + isValidKey, + } = useTritonChat(); + + useEffect(() => { + validateApiKey(); + }, []); + + return ( + + + {isValidKey ? ( + + ) : ( + + )} ); diff --git a/packages/site/src/providers/TritonProvider.tsx b/packages/site/src/providers/TritonProvider.tsx index 34112e3817..e27535ba4e 100644 --- a/packages/site/src/providers/TritonProvider.tsx +++ b/packages/site/src/providers/TritonProvider.tsx @@ -1,4 +1,5 @@ import { PropsWithChildren, createContext, useContext, useState } from "react"; +import { useTritonApi } from "../utils/useTritonApi"; interface TritonContextType { tritonOpen: boolean; @@ -7,6 +8,13 @@ interface TritonContextType { question: string; setQuestion: (question: string) => void; sendSearch: () => void; + setApiKey: (key: string) => Promise; + responses: string[]; + questions: string[]; + loading: boolean; + setLoading: (loading: boolean) => void; + validateApiKey: () => Promise; + isValidKey: boolean; } const TritonContext = createContext({ @@ -16,29 +24,42 @@ const TritonContext = createContext({ question: "", setQuestion: () => ({}), sendSearch: () => ({}), + setApiKey: async () => Promise.resolve(), + responses: [], + questions: [], + loading: false, + setLoading: () => ({}), + validateApiKey: async () => Promise.resolve(), + isValidKey: false, }); export function TritonProvider({ children }: PropsWithChildren) { const [tritonOpen, setTritonOpen] = useState(false); const [question, setQuestion] = useState(""); + const [responses, setResponses] = useState([]); + const [questions, setQuestions] = useState([]); + const [loading, setLoading] = useState(false); + const [isValidKey, setIsValidKey] = useState(false); + const { validateApiKey, sendSearch } = useTritonApi(); - const sendSearch = async () => { - console.log("searching!", question); - const b = await fetch("http://localhost:8788/stream", { - headers: { - "Content-Type": "application/json", - "Triton-Api-Key": localStorage.getItem("tritonApiKey") || "", - }, - method: "POST", - body: JSON.stringify({ - personality: "developer", - query: question, - questions: [], - questionType: "web", - responses: [], - }), + const handleValidateApiKey = async (key?: string) => { + return validateApiKey(setIsValidKey, setLoading, key); + }; + + const setApiKey = async (key: string) => { + await handleValidateApiKey(key); + }; + + const handleSendSearch = () => { + return sendSearch({ + question, + questions, + responses, + setLoading, + setQuestions, + setResponses, + setQuestion, }); - console.log("HI!", await b.json()); }; const value = { @@ -47,7 +68,14 @@ export function TritonProvider({ children }: PropsWithChildren) { onCloseTriton: () => setTritonOpen(false), question, setQuestion, - sendSearch, + sendSearch: handleSendSearch, + setApiKey, + responses, + questions, + loading, + setLoading, + validateApiKey: handleValidateApiKey, + isValidKey, }; return ( diff --git a/packages/site/src/utils/TritonLinks.ts b/packages/site/src/utils/TritonLinks.ts new file mode 100644 index 0000000000..c579c06851 --- /dev/null +++ b/packages/site/src/utils/TritonLinks.ts @@ -0,0 +1,20 @@ +import { componentList } from "../componentList"; +import { designList } from "../designList"; + +const componentEntries = componentList.map(({ title }) => [title, title]); +const designEntries = designList.map(({ title, to }) => [ + title, + to.replace("/design/", "design/"), +]); + +export const componentMap = Object.fromEntries([ + ...componentEntries, + ...designEntries, +]) as Record; + +export const getComponentPath = (componentName: string): string => { + const mapped = componentMap[componentName]; + if (!mapped) return "/components"; + + return mapped.startsWith("design/") ? `/${mapped}` : `/components/${mapped}`; +}; diff --git a/packages/site/src/utils/useTritonApi.ts b/packages/site/src/utils/useTritonApi.ts new file mode 100644 index 0000000000..498256c748 --- /dev/null +++ b/packages/site/src/utils/useTritonApi.ts @@ -0,0 +1,165 @@ +/* eslint-disable max-statements */ +interface TritonApiOptions { + endpoint: string; + body?: object; + key?: string; +} + +interface UseTritonApi { + invokeTritonApi: (options: TritonApiOptions) => Promise; + validateApiKey: ( + setIsValidKey: (isValid: boolean) => void, + setLoading: (loading: boolean) => void, + key?: string, + ) => Promise; + scrollToBottom: () => void; + sendSearch: (options: { + question: string; + questions: string[]; + responses: string[]; + setLoading: (loading: boolean) => void; + setQuestions: React.Dispatch>; + setResponses: React.Dispatch>; + setQuestion: (question: string) => void; + }) => Promise; +} + +const scrollToBottom = () => { + const container = document.querySelector("[data-conversation-container]"); + + if (container) { + container.scrollTop = container.scrollHeight; + } +}; + +export function useTritonApi(): UseTritonApi { + const invokeTritonApi = async ({ endpoint, body, key }: TritonApiOptions) => { + try { + const response = await fetch( + `https://atlantis-ai.jobber.dev${endpoint}`, + { + headers: { + "Content-Type": "application/json", + "Triton-Api-Key": key || localStorage.getItem("tritonApiKey") || "", + }, + method: "POST", + body: body ? JSON.stringify(body) : undefined, + }, + ); + + if (!response.ok) { + if (response.status === 401) { + throw new Error( + "Invalid Triton API key. Please update your API key in the Triton panel.", + ); + } + + throw new Error( + `Oops, something went wrong: ${response.status} ${response.statusText}`, + ); + } + + return response; + } catch (error) { + console.error("Fetch error:", error); + throw error; + } + }; + + const validateApiKey = async ( + setIsValidKey: (isValid: boolean) => void, + setLoading: (loading: boolean) => void, + key?: string, + ): Promise => { + const keyToValidate = key || localStorage.getItem("tritonApiKey"); + + if (!keyToValidate) { + setIsValidKey(false); + + return; + } + + try { + setLoading(true); + await invokeTritonApi({ endpoint: "/auth/verify", key: keyToValidate }); + + if (key) { + localStorage.setItem("tritonApiKey", key); + } + + setIsValidKey(true); + } catch (error) { + if (!key) { + localStorage.removeItem("tritonApiKey"); + } + setIsValidKey(false); + throw error; + } finally { + setLoading(false); + } + }; + + const sendSearch = async ({ + question, + questions, + responses, + setLoading, + setQuestions, + setResponses, + setQuestion, + }: { + question: string; + questions: string[]; + responses: string[]; + setLoading: (loading: boolean) => void; + setQuestions: React.Dispatch>; + setResponses: React.Dispatch>; + setQuestion: (question: string) => void; + }) => { + if (!question.trim()) return; + + try { + setLoading(true); + const response = await invokeTritonApi({ + endpoint: "/stream", + body: { + personality: "developer", + query: question, + questions, + questionType: "web", + responses, + }, + }); + + if (!response.body) return; + const reader = response.body.getReader(); + let chunks = ""; + let done, value; + + setQuestions(prev => [...prev, question]); + setResponses(prev => [...prev, ""]); + setQuestion(""); + + do { + ({ done, value } = await reader.read()); + + if (!done) { + chunks += new TextDecoder().decode(value); + setResponses(prev => { + const newResponses = [...prev]; + newResponses[newResponses.length - 1] = chunks; + + return newResponses; + }); + scrollToBottom(); + } + } while (!done); + } catch (error) { + console.error("Search failed:", error); + } finally { + setLoading(false); + } + }; + + return { invokeTritonApi, validateApiKey, scrollToBottom, sendSearch }; +} From 7c301298334dfbdd34531524cfe17049766d6e00 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Fri, 21 Feb 2025 15:33:18 -0800 Subject: [PATCH 20/28] remove overlay as the drawer covers the whole viewport --- .../site/src/layout/LeftDrawer.module.css | 10 ------- packages/site/src/layout/LeftDrawer.tsx | 29 +++++++++---------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/packages/site/src/layout/LeftDrawer.module.css b/packages/site/src/layout/LeftDrawer.module.css index b02f230f60..5df3aca48c 100644 --- a/packages/site/src/layout/LeftDrawer.module.css +++ b/packages/site/src/layout/LeftDrawer.module.css @@ -1,13 +1,3 @@ -.overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(var(--color-black--rgb), 0.4); - z-index: var(--elevation-modal); -} - .drawer { position: fixed; top: 0; diff --git a/packages/site/src/layout/LeftDrawer.tsx b/packages/site/src/layout/LeftDrawer.tsx index 5ee13183d7..7c693f4f60 100644 --- a/packages/site/src/layout/LeftDrawer.tsx +++ b/packages/site/src/layout/LeftDrawer.tsx @@ -17,21 +17,18 @@ export function LeftDrawer({ if (!open) return null; return ( - <> -
-
- -
- +
+ +
); } From 5f551715a4a7fedf8fb0f1bf60714e4367608775 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Fri, 21 Feb 2025 15:33:45 -0800 Subject: [PATCH 21/28] one more overlay css --- packages/site/src/layout/LeftDrawer.module.css | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/site/src/layout/LeftDrawer.module.css b/packages/site/src/layout/LeftDrawer.module.css index 5df3aca48c..2a5bbe3cbb 100644 --- a/packages/site/src/layout/LeftDrawer.module.css +++ b/packages/site/src/layout/LeftDrawer.module.css @@ -12,7 +12,6 @@ } @media screen and (min-width: 768px) { - .overlay, .drawer { display: none; } From 8de864cdcf86cca4fb4af65ddfba265ce5f3de51 Mon Sep 17 00:00:00 2001 From: Edi Yang Date: Fri, 21 Feb 2025 15:46:02 -0800 Subject: [PATCH 22/28] padding adjustment --- packages/site/src/layout/LeftDrawer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/site/src/layout/LeftDrawer.tsx b/packages/site/src/layout/LeftDrawer.tsx index 7c693f4f60..904bb3db48 100644 --- a/packages/site/src/layout/LeftDrawer.tsx +++ b/packages/site/src/layout/LeftDrawer.tsx @@ -18,7 +18,7 @@ export function LeftDrawer({ return (
- +