- {/* Header bar: Contains dataset, feature, color ramp, and other top-level functionality. */}
- {/* TODO: Split into its own component? */}
-
-
-
-
-
-
-
Timelapse Colorizer
-
+
{/*
Dataset Name
*/}
@@ -740,7 +718,7 @@ function Viewer(): ReactElement {
-
+
{/** Main Content: Contains canvas and plot, ramp controls, time controls, etc. */}
diff --git a/src/assets/AICS-logo-and-name.svg b/src/assets/AICS-logo-and-name.svg
index bd975ee28..60a595f94 100644
--- a/src/assets/AICS-logo-and-name.svg
+++ b/src/assets/AICS-logo-and-name.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
new file mode 100644
index 000000000..ee2c5040f
--- /dev/null
+++ b/src/components/Header.tsx
@@ -0,0 +1,75 @@
+import React, { PropsWithChildren, ReactElement } from "react";
+import { Link } from "react-router-dom";
+import styled from "styled-components";
+
+import { AicsLogoSVG } from "../assets";
+import { FlexRowAlignCenter } from "../styles/utils";
+
+const AicsLogoLink = styled.a`
+ position: relative;
+ width: 180px;
+ height: 46px;
+`;
+
+const StyledAicsLogo = styled(AicsLogoSVG)`
+ left: 0;
+ top: 0;
+ position: absolute;
+`;
+
+const VerticalDivider = styled.div`
+ height: 24px;
+ width: 1px;
+ background-color: var(--color-dividers);
+ display: inline-block;
+`;
+
+/**
+ * The logo and title of the app, to be used with the Header component.
+ * Both the logo and app title are links that can be used for navigation.
+ */
+function HeaderLogo(): ReactElement {
+ return (
+
+
+
+
+
+
+
Timelapse Colorizer
+
+
+ );
+}
+
+/**
+ * Top title bar for the app, which will stick to the top of the page.
+ * Child components will be spaced apart evenly.
+ * */
+const HeaderContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: space-between;
+ width: auto;
+ height: fit-content;
+ min-height: var(--header-content-height);
+ padding: 12px 30px;
+ border-bottom: 1px solid var(--color-borders);
+ gap: 10px;
+ position: sticky;
+ background-color: var(--color-background);
+ z-index: 100;
+ top: 0;
+ left: 0;
+`;
+
+export default function Header(props: PropsWithChildren): ReactElement {
+ return (
+
+
+ {props.children}
+
+ );
+}
diff --git a/src/routes/ErrorPage.tsx b/src/routes/ErrorPage.tsx
index f84a4bb41..bcef42eb0 100644
--- a/src/routes/ErrorPage.tsx
+++ b/src/routes/ErrorPage.tsx
@@ -4,6 +4,8 @@ import { ErrorResponse, Link, useRouteError } from "react-router-dom";
import { FlexColumnAlignCenter } from "../styles/utils";
+import Header from "../components/Header";
+
const isErrorResponse = (error: unknown): error is ErrorResponse => {
return typeof (error as ErrorResponse).status === "number" && typeof (error as ErrorResponse).statusText === "string";
};
@@ -21,13 +23,16 @@ export default function ErrorPage(): ReactElement {
}
return (
-
-