diff --git a/components/agility-common/LoadingWidget.js b/components/agility-common/LoadingWidget.js
new file mode 100644
index 000000000..a963b5b9f
--- /dev/null
+++ b/components/agility-common/LoadingWidget.js
@@ -0,0 +1,15 @@
+import { CgSpinner } from "react-icons/cg";
+
+const Widget = ({ message }) => {
+ return (
+
+ );
+};
+
+export default Widget;
diff --git a/components/agility-common/PreviewBar.js b/components/agility-common/PreviewBar.js
new file mode 100644
index 000000000..9c504059c
--- /dev/null
+++ b/components/agility-common/PreviewBar.js
@@ -0,0 +1,155 @@
+import React, { useState } from "react";
+import {
+ FaInfoCircle,
+ FaGithub,
+ FaChevronDown,
+ FaChevronUp,
+} from "react-icons/fa";
+
+/**
+ * This is a preview bar that is enabled by default to handle viewing content in preview & live mode, remove this for production use.
+ **/
+
+const PreviewBar = ({ isPreview, isDevelopmentMode }) => {
+ const [open, setOpen] = useState(false);
+
+ // handle view function to determine preview / live mode
+ const handleView = () => {
+ if (isDevelopmentMode) {
+ alert("You are currently in Development Mode, Live Mode is unavailable.");
+ } else {
+ if (!isDevelopmentMode && !isPreview) {
+ const xhr = new XMLHttpRequest();
+
+ xhr.onload = function () {
+ // Process our return data
+ if (xhr.status >= 200 && xhr.status < 300) {
+ // What do when the request is successful
+ const previewKey = xhr.responseText;
+
+ window.location.replace(
+ `${window.location.pathname}?agilitypreviewkey=${escape(
+ previewKey
+ )}`
+ );
+ }
+ };
+ // Create and send a GET request
+ xhr.open("GET", "/api/generatePreviewKey");
+ xhr.send();
+ } else {
+ const exit = confirm("Would you like to exit Preview Mode?");
+ if (exit === true) {
+ window.location.href = `/api/exitPreview?slug=${window.location.pathname}`;
+ } else return;
+ }
+ }
+ };
+
+ return (
+
+
+
+
+ {isPreview ? (
+
+ Previewing Latest Changes
+
+ ) : (
+
+ Viewing Published Content
+
+ )}
+
setOpen(!open)}
+ >
+ {open ? (
+
+ ) : (
+
+ )}
+
+
+ {isPreview ? (
+
+ Previewing Latest Changes
+
+ ) : (
+
+ Viewing Published Content
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default PreviewBar;
diff --git a/components/common/Layout/Layout.tsx b/components/common/Layout/Layout.tsx
index c7c35d767..065768302 100644
--- a/components/common/Layout/Layout.tsx
+++ b/components/common/Layout/Layout.tsx
@@ -13,122 +13,138 @@ import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
import { Sidebar, Button, Modal, LoadingDots } from '@components/ui'
import PaymentMethodView from '@components/checkout/PaymentMethodView'
import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView'
+import { handlePreview } from "@agility/nextjs";
import LoginView from '@components/auth/LoginView'
import s from './Layout.module.css'
+import LoadingWidget from '@components/agility-common/LoadingWidget'
+import PreviewBar from '@components/agility-common/PreviewBar'
const Loading = () => (
-
-
-
+
+
+
)
const dynamicProps = {
- loading: () => ,
+ loading: () => ,
}
const SignUpView = dynamic(
- () => import('@components/auth/SignUpView'),
- dynamicProps
+ () => import('@components/auth/SignUpView'),
+ dynamicProps
)
const ForgotPassword = dynamic(
- () => import('@components/auth/ForgotPassword'),
- dynamicProps
+ () => import('@components/auth/ForgotPassword'),
+ dynamicProps
)
const FeatureBar = dynamic(
- () => import('@components/common/FeatureBar'),
- dynamicProps
+ () => import('@components/common/FeatureBar'),
+ dynamicProps
)
interface Props {
- pageProps: {
- pages?: Page[]
- categories: Category[],
- agilityProps: any
- }
+ pageProps: {
+ pages?: Page[]
+ categories: Category[],
+ agilityProps: any
+ }
}
const ModalView: FC<{ modalView: string; closeModal(): any }> = ({
- modalView,
- closeModal,
+ modalView,
+ closeModal,
}) => {
- return (
-
- {modalView === 'LOGIN_VIEW' && }
- {modalView === 'SIGNUP_VIEW' && }
- {modalView === 'FORGOT_VIEW' && }
-
- )
+ return (
+
+ {modalView === 'LOGIN_VIEW' && }
+ {modalView === 'SIGNUP_VIEW' && }
+ {modalView === 'FORGOT_VIEW' && }
+
+ )
}
const ModalUI: FC = () => {
- const { displayModal, closeModal, modalView } = useUI()
- return displayModal ? (
-
- ) : null
+ const { displayModal, closeModal, modalView } = useUI()
+ return displayModal ? (
+
+ ) : null
}
const SidebarView: FC<{ sidebarView: string; closeSidebar(): any }> = ({
- sidebarView,
- closeSidebar,
+ sidebarView,
+ closeSidebar,
}) => {
- return (
-
- {sidebarView === 'CART_VIEW' && }
- {sidebarView === 'CHECKOUT_VIEW' && }
- {sidebarView === 'PAYMENT_VIEW' && }
- {sidebarView === 'SHIPPING_VIEW' && }
-
- )
+ return (
+
+ {sidebarView === 'CART_VIEW' && }
+ {sidebarView === 'CHECKOUT_VIEW' && }
+ {sidebarView === 'PAYMENT_VIEW' && }
+ {sidebarView === 'SHIPPING_VIEW' && }
+
+ )
}
const SidebarUI: FC = () => {
- const { displaySidebar, closeSidebar, sidebarView } = useUI()
- return displaySidebar ? (
-
- ) : null
+ const { displaySidebar, closeSidebar, sidebarView } = useUI()
+ return displaySidebar ? (
+
+ ) : null
}
const Layout: FC = (props) => {
+ // set up handle preview
+ const isPreviewLoading = handlePreview();
+
const {
children,
pageProps: { agilityProps, ...pageProps },
- } = props
+ } = props
- const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
- const { locale = 'en-US' } = useRouter()
+ const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
+ const { locale = 'en-US' } = useRouter()
- const categories = agilityProps?.globalData?.sitedata?.categoryLinks || []
+ const categories = agilityProps?.globalData?.sitedata?.categoryLinks || []
- const navBarlinks = categories.slice(0, 2).map((c:any) => ({
- label: c.name,
- href: `/search/${c.slug}`,
- }))
+ const navBarlinks = categories.slice(0, 2).map((c: any) => ({
+ label: c.name,
+ href: `/search/${c.slug}`,
+ }))
- return (
-
-
-
- {children}
-
-
-
- onAcceptCookies()}>
- Accept cookies
-
- }
- />
-
-
- )
+ return (
+
+
+
+
+ {isPreviewLoading &&
+
+ }
+ {!isPreviewLoading &&
+ <>
+
+
+ {children}
+
+
+
+ onAcceptCookies()}>
+ Accept cookies
+
+ }
+ />
+ >
+ }
+
+
+ )
}
export default Layout
diff --git a/package.json b/package.json
index 3c51b10c8..04d24cdc9 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-fast-marquee": "^1.1.3",
+ "react-icons": "^4.2.0",
"react-merge-refs": "^1.1.0",
"react-use-measure": "^2.0.4",
"shopify-buy": "^2.11.0",
diff --git a/pages/api/exitPreview.js b/pages/api/exitPreview.js
new file mode 100644
index 000000000..4e3b168d3
--- /dev/null
+++ b/pages/api/exitPreview.js
@@ -0,0 +1,9 @@
+export default async (req, res) => {
+ // Clears the preview mode cookies.
+ // This function accepts no arguments.
+ res.clearPreviewData()
+
+ // Redirect to the slug
+ res.writeHead(307, { Location: req.query.slug })
+ res.end()
+}
\ No newline at end of file
diff --git a/pages/api/generatePreviewKey.js b/pages/api/generatePreviewKey.js
new file mode 100644
index 000000000..0759814e0
--- /dev/null
+++ b/pages/api/generatePreviewKey.js
@@ -0,0 +1,12 @@
+import { generatePreviewKey } from "@agility/nextjs/node"
+
+export default async (req, res) => {
+
+ //TODO: Only generate the preview link if you are already in Preview!
+ //how can I check if i'm in preview mode already?
+
+ const previewKey = generatePreviewKey();
+
+ //Return a valid preview key
+ res.end(previewKey)
+}
\ No newline at end of file
diff --git a/pages/api/preview.js b/pages/api/preview.js
new file mode 100644
index 000000000..4cb0c386d
--- /dev/null
+++ b/pages/api/preview.js
@@ -0,0 +1,35 @@
+import { validatePreview, getDynamicPageURL } from '@agility/nextjs/node'
+
+// A simple example for testing it manually from your browser.
+// If this is located at pages/api/preview.js, then
+// open /api/preview from your browser.
+export default async (req, res) => {
+
+ //validate our preview key, also validate the requested page to preview exists
+ const validationResp = await validatePreview({
+ agilityPreviewKey: req.query.agilitypreviewkey,
+ slug: req.query.slug
+ });
+
+ if (validationResp.error) {
+ return res.status(401).end(`${validationResp.message}`)
+ }
+
+ let previewUrl = req.query.slug;
+
+ //TODO: these kinds of dynamic links should work by default (even outside of preview)
+ if(req.query.ContentID) {
+ const dynamicPath = await getDynamicPageURL({contentID: req.query.ContentID, preview: true, slug: req.query.slug});
+ if(dynamicPath) {
+ previewUrl = dynamicPath;
+ }
+ }
+
+ //enable preview mode
+ res.setPreviewData({})
+
+ // Redirect to the slug
+ res.writeHead(307, { Location: previewUrl })
+ res.end()
+
+}
\ No newline at end of file
diff --git a/public/assets/agility-logo.svg b/public/assets/agility-logo.svg
new file mode 100644
index 000000000..cb577be95
--- /dev/null
+++ b/public/assets/agility-logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/assets/agility-preview-logo.svg b/public/assets/agility-preview-logo.svg
new file mode 100644
index 000000000..53271d929
--- /dev/null
+++ b/public/assets/agility-preview-logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tailwind.config.js b/tailwind.config.js
index 8104d675a..030054843 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,71 +1,78 @@
module.exports = {
- future: {
- purgeLayersByDefault: true,
- applyComplexClasses: true,
- },
- purge: {
- content: [
- './pages/**/*.{js,ts,jsx,tsx}',
- './components/**/*.{js,ts,jsx,tsx}',
- ],
- options: {
- safelist: {
- standard: ['outline-none'],
- },
- },
- },
- theme: {
- extend: {
- maxWidth: {
- '8xl': '1920px',
- },
- colors: {
- primary: 'var(--primary)',
- 'primary-2': 'var(--primary-2)',
- secondary: 'var(--secondary)',
- 'secondary-2': 'var(--secondary-2)',
- hover: 'var(--hover)',
- 'hover-1': 'var(--hover-1)',
- 'hover-2': 'var(--hover-2)',
- 'accent-0': 'var(--accent-0)',
- 'accent-1': 'var(--accent-1)',
- 'accent-2': 'var(--accent-2)',
- 'accent-3': 'var(--accent-3)',
- 'accent-4': 'var(--accent-4)',
- 'accent-5': 'var(--accent-5)',
- 'accent-6': 'var(--accent-6)',
- 'accent-7': 'var(--accent-7)',
- 'accent-8': 'var(--accent-8)',
- 'accent-9': 'var(--accent-9)',
- violet: 'var(--violet)',
- 'violet-light': 'var(--violet-light)',
- 'violet-dark': 'var(--violet-dark)',
- pink: 'var(--pink)',
- 'pink-light': 'var(--pink-light)',
- cyan: 'var(--cyan)',
- blue: 'var(--blue)',
- green: 'var(--green)',
- red: 'var(--red)',
- },
- textColor: {
- base: 'var(--text-base)',
- primary: 'var(--text-primary)',
- secondary: 'var(--text-secondary)',
- },
- boxShadow: {
- 'outline-normal': '0 0 0 2px var(--accent-2)',
- magical:
- 'rgba(0, 0, 0, 0.02) 0px 30px 30px, rgba(0, 0, 0, 0.03) 0px 0px 8px, rgba(0, 0, 0, 0.05) 0px 1px 0px',
- },
- lineHeight: {
- 'extra-loose': '2.2',
- },
- scale: {
- 120: '1.2',
- },
- },
- },
- plugins: [
- require('@tailwindcss/typography'),
- ],
+ future: {
+ purgeLayersByDefault: true,
+ applyComplexClasses: true,
+ },
+ purge: {
+ content: [
+ './pages/**/*.{js,ts,jsx,tsx}',
+ './components/**/*.{js,ts,jsx,tsx}',
+ ],
+ options: {
+ safelist: {
+ standard: ['outline-none'],
+ },
+ },
+ },
+ theme: {
+ extend: {
+ maxWidth: {
+ '8xl': '1920px',
+ },
+ colors: {
+ transparent: "transparent",
+
+ black: "#000",
+ white: "#fff",
+
+ agility: "#222",
+
+ primary: 'var(--primary)',
+ 'primary-2': 'var(--primary-2)',
+ secondary: 'var(--secondary)',
+ 'secondary-2': 'var(--secondary-2)',
+ hover: 'var(--hover)',
+ 'hover-1': 'var(--hover-1)',
+ 'hover-2': 'var(--hover-2)',
+ 'accent-0': 'var(--accent-0)',
+ 'accent-1': 'var(--accent-1)',
+ 'accent-2': 'var(--accent-2)',
+ 'accent-3': 'var(--accent-3)',
+ 'accent-4': 'var(--accent-4)',
+ 'accent-5': 'var(--accent-5)',
+ 'accent-6': 'var(--accent-6)',
+ 'accent-7': 'var(--accent-7)',
+ 'accent-8': 'var(--accent-8)',
+ 'accent-9': 'var(--accent-9)',
+ violet: 'var(--violet)',
+ 'violet-light': 'var(--violet-light)',
+ 'violet-dark': 'var(--violet-dark)',
+ pink: 'var(--pink)',
+ 'pink-light': 'var(--pink-light)',
+ cyan: 'var(--cyan)',
+ blue: 'var(--blue)',
+ green: 'var(--green)',
+ red: 'var(--red)',
+ },
+ textColor: {
+ base: 'var(--text-base)',
+ primary: 'var(--text-primary)',
+ secondary: 'var(--text-secondary)',
+ },
+ boxShadow: {
+ 'outline-normal': '0 0 0 2px var(--accent-2)',
+ magical:
+ 'rgba(0, 0, 0, 0.02) 0px 30px 30px, rgba(0, 0, 0, 0.03) 0px 0px 8px, rgba(0, 0, 0, 0.05) 0px 1px 0px',
+ },
+ lineHeight: {
+ 'extra-loose': '2.2',
+ },
+ scale: {
+ 120: '1.2',
+ },
+ },
+ },
+ plugins: [
+ require('@tailwindcss/typography'),
+ ],
}
diff --git a/yarn.lock b/yarn.lock
index 007523185..ac2caa342 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5744,6 +5744,11 @@ react-fast-marquee@^1.1.3:
resolved "https://registry.yarnpkg.com/react-fast-marquee/-/react-fast-marquee-1.1.3.tgz#8f1f397c64258bdee0e915147d503828ab74d695"
integrity sha512-DIfrpWMgIHEoEPWKYzs5dnV5ZSMuu0+4ddRG4qB6Ee2zDi5LuPAGc1gnOceG8j8tvnuSrdkaqYYQwLZ61VzU5w==
+react-icons@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.2.0.tgz#6dda80c8a8f338ff96a1851424d63083282630d0"
+ integrity sha512-rmzEDFt+AVXRzD7zDE21gcxyBizD/3NqjbX6cmViAgdqfJ2UiLer8927/QhhrXQV7dEj/1EGuOTPp7JnLYVJKQ==
+
react-is@16.13.1, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"