From 3444949cae67308a2286812461979fb954a49bee Mon Sep 17 00:00:00 2001 From: Daven Quinn Date: Sat, 26 Oct 2024 15:06:41 -0500 Subject: [PATCH 1/2] Updated navbar styles --- .../map-interface/src/context-panel/index.ts | 51 ++++++++- .../src/context-panel/main.module.sass | 6 +- packages/map-interface/src/dev/map-page.ts | 15 ++- .../map-interface/stories/navbar.stories.ts | 108 ++++++++++++++++++ 4 files changed, 168 insertions(+), 12 deletions(-) create mode 100644 packages/map-interface/stories/navbar.stories.ts diff --git a/packages/map-interface/src/context-panel/index.ts b/packages/map-interface/src/context-panel/index.ts index 1b77112e..bef43cff 100644 --- a/packages/map-interface/src/context-panel/index.ts +++ b/packages/map-interface/src/context-panel/index.ts @@ -1,8 +1,9 @@ import { useMemo } from "react"; -import { Navbar, Button, InputGroup, Spinner, Card } from "@blueprintjs/core"; +import { Navbar, Button, Spinner, Card, Text } from "@blueprintjs/core"; import hyper from "@macrostrat/hyper"; import styles from "./main.module.sass"; import { useMapStatus } from "@macrostrat/mapbox-react"; +import { Spacer } from "@macrostrat/ui-components"; const h = hyper.styled(styles); @@ -12,15 +13,18 @@ export function LoadingButton({ isLoading = false, onClick, active = false, + large = false, icon = "menu", + style, }) { return h(Button, { className: "loading-button", icon: isLoading ? spinnerElement : icon, - large: false, + large, minimal: true, onClick, active: active && !isLoading, + style, }); } @@ -35,15 +39,52 @@ type AnyChildren = React.ReactNode | React.ReactFragment; export function FloatingNavbar({ className, children, + headerElement = null, + title = null, statusElement = null, + rightElement = null, + height, + width, + style = {}, }: { className?: string; - children?: AnyChildren; + children: AnyChildren; + rightElement?: AnyChildren; + headerElement?: AnyChildren; statusElement?: AnyChildren; + title?: string; + height?: number | string; + width?: number | string; + style?: React.CSSProperties; }) { - return h("div.searchbar-holder", { className }, [ + let _rightElement: React.ReactNode | null = null; + if (rightElement != null) { + _rightElement = h("div.right-element", rightElement); + } + + let _headerElement: React.ReactNode | null = headerElement; + if (title != null && _headerElement == null) { + if (typeof title === "string") { + _headerElement = h(Text, { tagName: "h2", ellipsize: true }, title); + } else { + _headerElement = title; + } + } + + if (_headerElement != null) { + _headerElement = h([_headerElement, h(Spacer)]); + } + + return h("div.searchbar-holder", { className, style: { width } }, [ h("div.navbar-holder", [ - h(Navbar, { className: "searchbar panel" }, children), + h( + Navbar, + { + className: "searchbar navbar panel", + style: { height, ...style }, + }, + [_headerElement, children, _rightElement] + ), ]), h.if(statusElement != null)( Card, diff --git a/packages/map-interface/src/context-panel/main.module.sass b/packages/map-interface/src/context-panel/main.module.sass index 5d16af91..83527821 100644 --- a/packages/map-interface/src/context-panel/main.module.sass +++ b/packages/map-interface/src/context-panel/main.module.sass @@ -10,7 +10,7 @@ width: 100% background-color: var(--panel-background-color) border-radius: 5px - padding: 0 5px + padding: var(--navbar-padding, 10px) display: flex flex-direction: row align-items: center @@ -19,6 +19,9 @@ flex-grow: 1 cursor: text +.navbar + min-height: 50px + :global(.bp5-navbar)>.loading-button width: 40px height: 40px @@ -29,6 +32,7 @@ margin-top: -12px padding: 0 padding-top: 12px + overflow: hidden @media screen and (max-width: 768px) .status-tongue diff --git a/packages/map-interface/src/dev/map-page.ts b/packages/map-interface/src/dev/map-page.ts index 69ad276c..171500f1 100644 --- a/packages/map-interface/src/dev/map-page.ts +++ b/packages/map-interface/src/dev/map-page.ts @@ -33,7 +33,6 @@ export function MapInspector({ focusedSource = null, focusedSourceTitle = null, fitViewport = true, - projection = null, }: { headerElement?: React.ReactElement; transformRequest?: mapboxgl.TransformRequestFunction; @@ -127,14 +126,18 @@ export function MapInspector({ return h( MapAreaContainer, { - navbar: h(FloatingNavbar, [ - headerElement ?? h("h2", title), - h(Spacer), - h(MapLoadingButton, { + navbar: h(FloatingNavbar, { + rightElement: h(MapLoadingButton, { + large: true, active: isOpen, onClick: () => setOpen(!isOpen), + style: { + marginRight: "-5px", + }, }), - ]), + headerElement, + title, + }), contextPanel: h(PanelCard, [ h(Switch, { checked: xRay, diff --git a/packages/map-interface/stories/navbar.stories.ts b/packages/map-interface/stories/navbar.stories.ts new file mode 100644 index 00000000..c5277ff1 --- /dev/null +++ b/packages/map-interface/stories/navbar.stories.ts @@ -0,0 +1,108 @@ +import h from "@macrostrat/hyper"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { Text } from "@blueprintjs/core"; +import { FloatingNavbar, MapLoadingButton } from "../src"; +import { Box } from "@macrostrat/ui-components"; + +interface BasicNavbarProps { + title: string; + width: number | string | null; + height: number | string | null; +} + +function BasicNavbar(props: BasicNavbarProps) { + return h(FloatingNavbar, { + rightElement: h(MapLoadingButton), + ...props, + }); +} + +// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export +const meta: Meta = { + title: "Map interface/Components/Floating navbar", + component: BasicNavbar, +}; + +export default meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + title: "Map inspector", + width: 250, + }, + argTypes: { + title: { + type: { + name: "string", + required: true, + }, + default: "Map inspector", + }, + }, +}; + +export const WithStatusBar: Story = { + args: { + title: "A map", + width: 250, + statusElement: h( + Box, + { + paddingX: 10, + paddingY: 2, + backgroundColor: "rgba(255 200 200)", + color: "red", + }, + "Bad stuff is afoot" + ), + }, +}; + +export const NoTitle: Story = { + args: { + title: null, + width: "fit-content", + style: { padding: 5 }, + rightElement: h(MapLoadingButton, { + large: true, + }), + }, +}; + +export const LongTitleWrapped: Story = { + args: { + title: h( + Text, + { + tagName: "h2", + style: { margin: 0 }, + }, + "This is a long title that should wrap" + ), + width: 250, + height: "fit-content", + }, +}; + +export const LongTitleOverflow: Story = { + args: { + title: "This is a long title that should overflow", + width: 250, + }, +}; + +export const UnlimitedWidth: Story = { + args: { + title: "Map inspector", + }, +}; + +export const WidthFollowsContent: Story = { + args: { + title: "Map inspector (width follows content)", + width: "fit-content", + }, +}; From 12ada8874f00ae19a1f9e3909d34f19a983e71b3 Mon Sep 17 00:00:00 2001 From: Daven Quinn Date: Sat, 26 Oct 2024 18:49:05 -0500 Subject: [PATCH 2/2] Updated navbar styles again --- .../map-interface/src/context-panel/index.ts | 24 +++++++------- .../map-interface/stories/navbar.stories.ts | 33 ++++++++++++------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/packages/map-interface/src/context-panel/index.ts b/packages/map-interface/src/context-panel/index.ts index bef43cff..6d9ab099 100644 --- a/packages/map-interface/src/context-panel/index.ts +++ b/packages/map-interface/src/context-panel/index.ts @@ -36,6 +36,18 @@ export function MapLoadingButton(props) { type AnyChildren = React.ReactNode | React.ReactFragment; +export interface FloatingNavbarProps { + className?: string; + children: AnyChildren; + headerElement?: AnyChildren; + title?: AnyChildren; + statusElement?: AnyChildren; + rightElement?: AnyChildren; + height: number | string; + width: number | string; + style?: object; +} + export function FloatingNavbar({ className, children, @@ -46,17 +58,7 @@ export function FloatingNavbar({ height, width, style = {}, -}: { - className?: string; - children: AnyChildren; - rightElement?: AnyChildren; - headerElement?: AnyChildren; - statusElement?: AnyChildren; - title?: string; - height?: number | string; - width?: number | string; - style?: React.CSSProperties; -}) { +}: FloatingNavbarProps) { let _rightElement: React.ReactNode | null = null; if (rightElement != null) { _rightElement = h("div.right-element", rightElement); diff --git a/packages/map-interface/stories/navbar.stories.ts b/packages/map-interface/stories/navbar.stories.ts index c5277ff1..07966ee6 100644 --- a/packages/map-interface/stories/navbar.stories.ts +++ b/packages/map-interface/stories/navbar.stories.ts @@ -1,17 +1,11 @@ import h from "@macrostrat/hyper"; import type { Meta, StoryObj } from "@storybook/react"; -import { Text } from "@blueprintjs/core"; -import { FloatingNavbar, MapLoadingButton } from "../src"; +import { Breadcrumbs, Text } from "@blueprintjs/core"; +import { FloatingNavbar, MapLoadingButton, FloatingNavbarProps } from "../src"; import { Box } from "@macrostrat/ui-components"; -interface BasicNavbarProps { - title: string; - width: number | string | null; - height: number | string | null; -} - -function BasicNavbar(props: BasicNavbarProps) { +function BasicNavbar(props: FloatingNavbarProps) { return h(FloatingNavbar, { rightElement: h(MapLoadingButton), ...props, @@ -19,14 +13,14 @@ function BasicNavbar(props: BasicNavbarProps) { } // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export -const meta: Meta = { +const meta: Meta = { title: "Map interface/Components/Floating navbar", component: BasicNavbar, }; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const Primary: Story = { args: { @@ -61,7 +55,22 @@ export const WithStatusBar: Story = { }, }; -export const NoTitle: Story = { +export const WithExpandedNavigation: Story = { + args: { + headerElement: h( + Box, + { display: "flex", flexDirection: "column", gap: 5, marginX: 5 }, + [ + h(Breadcrumbs, { items: [{ icon: "home" }, { text: "Map" }] }), + h(Text, { tagName: "h3", style: { margin: 0 } }, "Map inspector"), + ] + ), + width: 250, + height: "fit-content", + }, +}; + +export const WithoutTitle: Story = { args: { title: null, width: "fit-content",