diff --git a/tailwind.config.js b/tailwind.config.js
index 86257133..609f2c39 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -9,6 +9,9 @@ export default {
extend: {
colors: {
primary: { "50": "#eff6ff", "100": "#dbeafe", "200": "#bfdbfe", "300": "#93c5fd", "400": "#60a5fa", "500": "#3b82f6", "600": "#2563eb", "700": "#1d4ed8", "800": "#1e40af", "900": "#1e3a8a", "950": "#172554" }
+ },
+ fontFamily: {
+ 'montserrat': ['Montserrat'],
}
},
},
From dbe18d40e770b7bc4ff3b4c13251254ef910c8d7 Mon Sep 17 00:00:00 2001
From: Pedro Rodrigues
Date: Thu, 22 Feb 2024 14:47:39 +0000
Subject: [PATCH 3/4] change logo h1 font weight to bold
---
src/components/common/Logo.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/common/Logo.tsx b/src/components/common/Logo.tsx
index 84143b91..540350c2 100644
--- a/src/components/common/Logo.tsx
+++ b/src/components/common/Logo.tsx
@@ -12,7 +12,7 @@ const Logo: FC = ({
return (
-
Ward Analytics
+
Ward Analytics
)
}
From 5e99d38fc2489f9b9bff5502a005122237b49d89 Mon Sep 17 00:00:00 2001
From: Pedro Rodrigues
Date: Thu, 22 Feb 2024 15:21:58 +0000
Subject: [PATCH 4/4] add helmet elements to each routed page
---
package.json | 1 +
src/App.tsx | 19 ++++--
src/components/common/SEO.tsx | 42 ++++++++++++
src/templates/BillingTemplate.tsx | 94 ++++++++++++++------------
src/templates/SavedGraphTemplate.tsx | 16 +++--
src/templates/SavedGraphsTemplate.tsx | 52 +++++++-------
src/templates/UnsavedGraphTemplate.tsx | 64 ++++++++++--------
yarn.lock | 28 +++++++-
8 files changed, 204 insertions(+), 112 deletions(-)
create mode 100644 src/components/common/SEO.tsx
diff --git a/package.json b/package.json
index 4a5a9788..d7621207 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-draggable": "^4.4.6",
+ "react-helmet-async": "^2.0.4",
"react-hook-form": "^7.50.1",
"react-icons": "^5.0.1",
"react-query": "^3.39.3",
diff --git a/src/App.tsx b/src/App.tsx
index 9d7e3126..92a1b85c 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -7,18 +7,25 @@ import PrivateApp from "./PrivateApp";
import PublicApp from "./PublicApp";
import { MobileWarningTemplate } from "./templates";
+import { HelmetProvider } from 'react-helmet-async';
+
function App() {
const queryClient = useCustomQueryClient();
const { isAuthenticated } = useAuthState();
+ // Ensure that context is never scoped outside of the current instance of the app
+ const helmetContext = {};
+
return (
<>
-
-
-
- {isAuthenticated ?
:
}
-
-
+
+
+
+
+ {isAuthenticated ?
:
}
+
+
+
>
);
}
diff --git a/src/components/common/SEO.tsx b/src/components/common/SEO.tsx
new file mode 100644
index 00000000..e2e30121
--- /dev/null
+++ b/src/components/common/SEO.tsx
@@ -0,0 +1,42 @@
+import { FC } from "react";
+import { Helmet } from "react-helmet-async";
+
+interface SEOProps {
+ title: string;
+ description: string;
+ creator?: string;
+ type?: string;
+}
+
+const SEO: FC = ({
+ title,
+ description,
+ creator = "Ward Analytics",
+ type = "website",
+}) => {
+ return (
+
+ { /* Standard metadata tags */}
+ {`Ward Analytics - ${title}`}
+
+ { /* End standard metadata tags */}
+ { /* Facebook tags
+ For more information, visit https://ogp.me/
+ */}
+
+
+
+ { /* End Facebook tags */}
+ { /* Twitter tags
+ For more information, visit https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/summary
+ */}
+
+
+
+
+ { /* End Twitter tags */}
+
+ )
+}
+
+export default SEO;
\ No newline at end of file
diff --git a/src/templates/BillingTemplate.tsx b/src/templates/BillingTemplate.tsx
index d03d6805..c06dc4ad 100644
--- a/src/templates/BillingTemplate.tsx
+++ b/src/templates/BillingTemplate.tsx
@@ -19,6 +19,7 @@ import {
useCustomerPortalUrl,
} from "../services/stripe";
import { Colors } from "../utils/colors";
+import SEO from "../components/common/SEO";
interface PlanProps {
isPro: boolean;
@@ -261,54 +262,57 @@ const BillingTemplate: FC = () => {
}, [customerPortalUrl]);
return (
-
-
-
- Plan & Billing
-
-
+ <>
+
+
+
+
+ Plan & Billing
+
+
- {
- // TODO: Replace for a loading component to standardize the loading state
+ {
+ // TODO: Replace for a loading component to standardize the loading state
- <>
-
-
- Plan:
- {isLoading ? (
-
- ) : isPro ? (
-
-
- Pro
-
- ) : (
- Free
+ <>
+
+
+ Plan:
+ {isLoading ? (
+
+ ) : isPro ? (
+
+
+ Pro
+
+ ) : (
+ Free
+ )}
+
+ {isPro && (
+ setManageSubscriptionClicked(true)}
+ Icon={CreditCardSmallIcon}
+ />
)}
-
- {isPro && (
- setManageSubscriptionClicked(true)}
- Icon={CreditCardSmallIcon}
- />
- )}
-
-
- <>
-
-
-
- >
-
- >
- }
-
+
+
+ <>
+
+
+
+ >
+
+ >
+ }
+
+ >
);
};
diff --git a/src/templates/SavedGraphTemplate.tsx b/src/templates/SavedGraphTemplate.tsx
index e1bf5971..19fdb6a0 100644
--- a/src/templates/SavedGraphTemplate.tsx
+++ b/src/templates/SavedGraphTemplate.tsx
@@ -9,6 +9,7 @@ import {
import { Graph } from "../components/graph/Graph";
import { PersonalGraph } from "../services/firestore/user/graph_saving";
import useAuthState from "../hooks/useAuthState";
+import SEO from "../components/common/SEO";
const SavedGraphTemplate: FC = () => {
const { user } = useAuthState();
@@ -49,12 +50,15 @@ const SavedGraphTemplate: FC = () => {
if (!graph) return null;
return (
-
+ <>
+
+
+ >
);
};
diff --git a/src/templates/SavedGraphsTemplate.tsx b/src/templates/SavedGraphsTemplate.tsx
index 722e86ae..e2318403 100644
--- a/src/templates/SavedGraphsTemplate.tsx
+++ b/src/templates/SavedGraphsTemplate.tsx
@@ -19,6 +19,7 @@ import { PlusCircleIcon } from "@heroicons/react/20/solid";
import { useNavigate } from "react-router-dom";
import CreateGraphDialog from "../components/common/CreateGraphDialog";
import DeleteGraphDialog from "../components/common/DeleteGraphDialog";
+import SEO from "../components/common/SEO";
const GraphCard: FC<{ graph: PersonalGraph }> = ({ graph }) => {
const navigate = useNavigate();
@@ -60,33 +61,36 @@ const SavedGraphsTemplate: FC = () => {
const [isCreateGraphDialogOpen, setIsCreateGraphDialogOpen] = useState(false);
return (
-
-
-
-
- Saved Graphs
+ <>
+
+
+
+
+
+ Saved Graphs
+
+ {
+ setIsCreateGraphDialogOpen(true);
+ }}
+ Icon={PlusCircleIcon}
+ />
+
+
+
+
+ {graphs.map((graph) => (
+
+ ))}
+
-
{
- setIsCreateGraphDialogOpen(true);
- }}
- Icon={PlusCircleIcon}
+
-
-
-
-
- {graphs.map((graph) => (
-
- ))}
-
-
-
+ >
);
};
diff --git a/src/templates/UnsavedGraphTemplate.tsx b/src/templates/UnsavedGraphTemplate.tsx
index 2b54c253..de829ede 100644
--- a/src/templates/UnsavedGraphTemplate.tsx
+++ b/src/templates/UnsavedGraphTemplate.tsx
@@ -3,6 +3,7 @@ import { useParams } from "react-router-dom";
import { SharableGraph, getSharableGraph } from "../services/firestore/graph_sharing";
import { Transition } from "@headlessui/react";
+import SEO from "../components/common/SEO";
import { Graph } from "../components/graph/Graph";
import LandingPage from "../components/graph/landing_page/LandingPage";
@@ -81,36 +82,39 @@ const UnsavedGraphTemplate: FC
= ({
if (loading) return null;
return (
-
-
- {
- setGraph({ addresses: [address], edges: [] });
- }}
- />
-
- 0 || !showLandingPage}
- appear={true}
- enter="transition-all duration-500 delay-500"
- enterFrom="opacity-0 scale-150"
- enterTo="opacity-100 scale-100"
- className="h-full w-full"
- >
-
-
-
+ <>
+
+
+
+ {
+ setGraph({ addresses: [address], edges: [] });
+ }}
+ />
+
+ 0 || !showLandingPage}
+ appear={true}
+ enter="transition-all duration-500 delay-500"
+ enterFrom="opacity-0 scale-150"
+ enterTo="opacity-100 scale-100"
+ className="h-full w-full"
+ >
+
+
+
+ >
);
};
diff --git a/yarn.lock b/yarn.lock
index ae9753ca..42803d7a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3472,6 +3472,13 @@ internal-slot@^1.0.5:
hasown "^2.0.0"
side-channel "^1.0.4"
+invariant@^2.2.4:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+ integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+ dependencies:
+ loose-envify "^1.0.0"
+
is-array-buffer@^3.0.1, is-array-buffer@^3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz"
@@ -3948,7 +3955,7 @@ long@^5.0.0:
resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz"
integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
-loose-envify@^1.1.0, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -4623,6 +4630,20 @@ react-draggable@^4.4.6:
clsx "^1.1.1"
prop-types "^15.8.1"
+react-fast-compare@^3.2.2:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
+ integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
+
+react-helmet-async@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-2.0.4.tgz#50a4377778f380ed1d0136303916b38eff1bf153"
+ integrity sha512-yxjQMWposw+akRfvpl5+8xejl4JtUlHnEBcji6u8/e6oc7ozT+P9PNTWMhCbz2y9tc5zPegw2BvKjQA+NwdEjQ==
+ dependencies:
+ invariant "^2.2.4"
+ react-fast-compare "^3.2.2"
+ shallowequal "^1.1.0"
+
react-hook-form@^7.50.1:
version "7.50.1"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.50.1.tgz#f6aeb17a863327e5a0252de8b35b4fc8990377ed"
@@ -4929,6 +4950,11 @@ set-function-name@^2.0.0, set-function-name@^2.0.1:
functions-have-names "^1.2.3"
has-property-descriptors "^1.0.0"
+shallowequal@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
+ integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"