preview bar

This commit is contained in:
Joel Varty 2021-06-23 10:21:22 -04:00
parent 4929032e5f
commit 00922a8c7d
11 changed files with 396 additions and 139 deletions

View File

@ -0,0 +1,15 @@
import { CgSpinner } from "react-icons/cg";
const Widget = ({ message }) => {
return (
<section
id="loading-widget"
className="flex flex-col items-center justify-center h-screen"
>
<CgSpinner className="animate-spin text-2xl mb-2" />
<p>{message}</p>
</section>
);
};
export default Widget;

View File

@ -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 (
<div className="bg-agility relative px-8 text-gray-200">
<div className="flex justify-between items-center max-w-screen-xl mx-auto">
<div className="flex items-center">
<span className="p-2 rounded-lg mr-4">
<a
href="https://www.agilitycms.com"
target="_blank"
title="Agility CMS"
>
<img
src="https://static.agilitycms.com/brand/agility-triangle-yellow.svg"
alt="Agility CMS"
className="w-5 h-5 block md:hidden"
/>
<img
src="/assets/agility-preview-logo.svg"
alt="Agility CMS"
className="h-5 w-20 hidden md:block"
/>
</a>
</span>
<div className="mr-4">
<a
href="https://help.agilitycms.com/hc/en-us"
target="_blank"
title="Help Center"
>
<div className="flex items-center">
<FaInfoCircle className="text-2xl mr-2" />
<p className="hidden md:block text-sm">Help Center</p>
</div>
</a>
</div>
<div>
<a
href="https://github.com/agility/agilitycms-nextjs-starter"
target="_blank"
title="View on GitHub"
className="text-2xl"
>
<div className="flex items-center">
<FaGithub className="mr-2" />
<p className="hidden md:block text-sm">View on GitHub</p>
</div>
</a>
</div>
</div>
<div
className={`relative flex items-center ${
open ? `bg-white ` : `bg-agility`
} py-4`}
>
{isPreview ? (
<p
className={`hidden md:block text-sm px-2 ${
open ? `text-agility` : `text-gray-200`
}`}
>
Previewing <span className="font-bold">Latest</span> Changes
</p>
) : (
<p
className={`hidden md:block text-sm px-2 ${
open ? `text-agility` : `text-gray-200`
}`}
>
Viewing <span className="font-bold">Published</span> Content
</p>
)}
<div
className="p-2 text-gray-200 rounded-lg cursor-pointer z-50"
onClick={() => setOpen(!open)}
>
{open ? (
<FaChevronUp className="text-agility" />
) : (
<FaChevronDown className="text-gray-200" />
)}
</div>
<div
className="absolute bg-white text-white text-sm py-4 px-4 -right-0 -bottom-28 md:-bottom-16 z-50 rounded-b-lg shadow-xl md:max-w-full"
style={{ display: open ? "block" : "none", width: "15.1rem" }}
>
{isPreview ? (
<p className="mb-4 text-center md:hidden text-agility z-20">
Previewing <span className="font-bold">Latest</span> Changes
</p>
) : (
<p className="mb-4 text-center md:hidden text-agility z-20">
Viewing <span className="font-bold">Published</span> Content
</p>
)}
<button
className="text-gray-200 bg-agility p-2 w-full rounded-md text-sm"
onClick={() => handleView()}
>
{`View ${isPreview ? `Live` : `Preview`} Mode`}
</button>
</div>
</div>
</div>
</div>
);
};
export default PreviewBar;

View File

@ -13,9 +13,12 @@ import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
import { Sidebar, Button, Modal, LoadingDots } from '@components/ui' import { Sidebar, Button, Modal, LoadingDots } from '@components/ui'
import PaymentMethodView from '@components/checkout/PaymentMethodView' import PaymentMethodView from '@components/checkout/PaymentMethodView'
import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView' import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView'
import { handlePreview } from "@agility/nextjs";
import LoginView from '@components/auth/LoginView' import LoginView from '@components/auth/LoginView'
import s from './Layout.module.css' import s from './Layout.module.css'
import LoadingWidget from '@components/agility-common/LoadingWidget'
import PreviewBar from '@components/agility-common/PreviewBar'
const Loading = () => ( const Loading = () => (
<div className="w-80 h-80 flex items-center text-center justify-center p-3"> <div className="w-80 h-80 flex items-center text-center justify-center p-3">
@ -93,6 +96,9 @@ const SidebarUI: FC = () => {
const Layout: FC<Props> = (props) => { const Layout: FC<Props> = (props) => {
// set up handle preview
const isPreviewLoading = handlePreview();
const { const {
children, children,
pageProps: { agilityProps, ...pageProps }, pageProps: { agilityProps, ...pageProps },
@ -111,7 +117,15 @@ const Layout: FC<Props> = (props) => {
return ( return (
<CommerceProvider locale={locale}> <CommerceProvider locale={locale}>
<div className={cn(s.root)}> <div className={cn(s.root)}>
{isPreviewLoading &&
<LoadingWidget message="Loading Preview Mode" />
}
{!isPreviewLoading &&
<>
<PreviewBar isDevelopmentMode={agilityProps.isDevelopmentMode} isPreview={agilityProps.isPreview}/>
<Navbar links={navBarlinks} agilityProps={agilityProps} /> <Navbar links={navBarlinks} agilityProps={agilityProps} />
<main className="fit">{children}</main> <main className="fit">{children}</main>
<Footer pages={pageProps.pages} agilityProps={agilityProps} /> <Footer pages={pageProps.pages} agilityProps={agilityProps} />
@ -126,6 +140,8 @@ const Layout: FC<Props> = (props) => {
</Button> </Button>
} }
/> />
</>
}
</div> </div>
</CommerceProvider> </CommerceProvider>
) )

View File

@ -53,6 +53,7 @@
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-fast-marquee": "^1.1.3", "react-fast-marquee": "^1.1.3",
"react-icons": "^4.2.0",
"react-merge-refs": "^1.1.0", "react-merge-refs": "^1.1.0",
"react-use-measure": "^2.0.4", "react-use-measure": "^2.0.4",
"shopify-buy": "^2.11.0", "shopify-buy": "^2.11.0",

9
pages/api/exitPreview.js Normal file
View File

@ -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()
}

View File

@ -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)
}

35
pages/api/preview.js Normal file
View File

@ -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()
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 247.19 63.55"><defs><style>.cls-1{fill:#717171;}.cls-1,.cls-2{fill-rule:evenodd;}.cls-2{fill:#ffcb28;}</style></defs><title>Asset 1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="Layer_1-2-2" data-name="Layer 1-2"><path class="cls-1" d="M99.51,48.14a21.07,21.07,0,0,0,6.91-1.08V40.51A17.66,17.66,0,0,0,98.94,39c-3.71,0-6.34,1.2-6.34,4.27,0,2.91,2.28,4.84,6.91,4.84M110.93,34.3V49.63a27.11,27.11,0,0,1-11.47,2.62c-8.23,0-11.6-3.76-11.6-8.72,0-5.47,4.8-8.54,11.08-8.54a19.91,19.91,0,0,1,7.48,1.36V34.3c0-4-2.62-6.2-7.36-6.2a13,13,0,0,0-7.66,2.45,4.25,4.25,0,0,1-2.34-3.08c1.71-1.71,5.65-3.65,10.22-3.65,6.46,0,11.65,3,11.65,10.48m28.38,10.48v-15A10.07,10.07,0,0,0,133.25,28c-5.71,0-9.65,3.93-9.65,9.57s3.94,9.17,9.65,9.17a9.17,9.17,0,0,0,6.06-2m4.62-17.48v23.5c0,6.72-5.19,11.85-12.85,11.85-4.74,0-9-1.48-11.76-4.67a5.41,5.41,0,0,1,3-3.13,11.06,11.06,0,0,0,8.79,3.7c5.71,0,8.23-3.42,8.23-7.75V49.23a14.25,14.25,0,0,1-6.46,1.59c-7.65,0-14-5-14-13.21,0-8,6-13.79,14.39-13.79A17.84,17.84,0,0,1,144,27.3m9.9,24.51V24.93a11.46,11.46,0,0,1,2.34-.23,10.35,10.35,0,0,1,2.29.23V51.82a12.43,12.43,0,0,1-4.63,0m-1-34.75a3.26,3.26,0,1,1,3.31,3.25,3.26,3.26,0,0,1-3.31-3.25v0m16,34.4V14.05a11.64,11.64,0,0,1,4.63,0V51.48a11.55,11.55,0,0,1-2.35.22,10.88,10.88,0,0,1-2.28-.22m15,.34V24.93a11.46,11.46,0,0,1,2.34-.23,10.35,10.35,0,0,1,2.29.23V51.82a12.43,12.43,0,0,1-4.63,0m-1-34.75a3.26,3.26,0,1,1,3.31,3.25,3.26,3.26,0,0,1-3.31-3.25v0m34.76,32.71a11.62,11.62,0,0,1-7.54,2.85c-5.42,0-9.37-2.57-9.37-9V29h-4.62a7,7,0,0,1-.23-1.88,6.66,6.66,0,0,1,.23-1.83h4.62V18.05a10.35,10.35,0,0,1,2.29-.23,9.82,9.82,0,0,1,2.23.23v7.24H215.9a6.58,6.58,0,0,1,.22,1.82A7,7,0,0,1,215.9,29H205.23V42.71c0,4.84,2.28,5.87,5.19,5.87a8.81,8.81,0,0,0,5.14-2,5.16,5.16,0,0,1,2.06,3.25m29.57-24.39c-4.45,17-9.54,27.23-19.53,38.11a4.55,4.55,0,0,1-3.26-2.79,63,63,0,0,0,7.26-9.4,98.66,98.66,0,0,1-10.8-26.09,9.55,9.55,0,0,1,2.86-.4,12.79,12.79,0,0,1,2.05.17A103.05,103.05,0,0,0,234,46.58l.45.86c.12-.29.29-.52.4-.8A91.25,91.25,0,0,0,242.51,25a11.84,11.84,0,0,1,1.88-.17,7.91,7.91,0,0,1,2.8.57"/><path class="cls-2" d="M42.92,53.29H17.28L36.61,19.9,55.94,53.29l5.64,9.94H73.22L36.61,0,0,63.23H47.42Z"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 247.19 63.55"><defs><style>.cls-1{fill:#fff;}.cls-1,.cls-2{fill-rule:evenodd;}.cls-2{fill:#ffcb28;}</style></defs><title>Asset 1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="Layer_1-2-2" data-name="Layer 1-2"><path class="cls-1" d="M99.51,48.14a21.07,21.07,0,0,0,6.91-1.08V40.51A17.66,17.66,0,0,0,98.94,39c-3.71,0-6.34,1.2-6.34,4.27,0,2.91,2.28,4.84,6.91,4.84M110.93,34.3V49.63a27.11,27.11,0,0,1-11.47,2.62c-8.23,0-11.6-3.76-11.6-8.72,0-5.47,4.8-8.54,11.08-8.54a19.91,19.91,0,0,1,7.48,1.36V34.3c0-4-2.62-6.2-7.36-6.2a13,13,0,0,0-7.66,2.45,4.25,4.25,0,0,1-2.34-3.08c1.71-1.71,5.65-3.65,10.22-3.65,6.46,0,11.65,3,11.65,10.48m28.38,10.48v-15A10.07,10.07,0,0,0,133.25,28c-5.71,0-9.65,3.93-9.65,9.57s3.94,9.17,9.65,9.17a9.17,9.17,0,0,0,6.06-2m4.62-17.48v23.5c0,6.72-5.19,11.85-12.85,11.85-4.74,0-9-1.48-11.76-4.67a5.41,5.41,0,0,1,3-3.13,11.06,11.06,0,0,0,8.79,3.7c5.71,0,8.23-3.42,8.23-7.75V49.23a14.25,14.25,0,0,1-6.46,1.59c-7.65,0-14-5-14-13.21,0-8,6-13.79,14.39-13.79A17.84,17.84,0,0,1,144,27.3m9.9,24.51V24.93a11.46,11.46,0,0,1,2.34-.23,10.35,10.35,0,0,1,2.29.23V51.82a12.43,12.43,0,0,1-4.63,0m-1-34.75a3.26,3.26,0,1,1,3.31,3.25,3.26,3.26,0,0,1-3.31-3.25v0m16,34.4V14.05a11.64,11.64,0,0,1,4.63,0V51.48a11.55,11.55,0,0,1-2.35.22,10.88,10.88,0,0,1-2.28-.22m15,.34V24.93a11.46,11.46,0,0,1,2.34-.23,10.35,10.35,0,0,1,2.29.23V51.82a12.43,12.43,0,0,1-4.63,0m-1-34.75a3.26,3.26,0,1,1,3.31,3.25,3.26,3.26,0,0,1-3.31-3.25v0m34.76,32.71a11.62,11.62,0,0,1-7.54,2.85c-5.42,0-9.37-2.57-9.37-9V29h-4.62a7,7,0,0,1-.23-1.88,6.66,6.66,0,0,1,.23-1.83h4.62V18.05a10.35,10.35,0,0,1,2.29-.23,9.82,9.82,0,0,1,2.23.23v7.24H215.9a6.58,6.58,0,0,1,.22,1.82A7,7,0,0,1,215.9,29H205.23V42.71c0,4.84,2.28,5.87,5.19,5.87a8.81,8.81,0,0,0,5.14-2,5.16,5.16,0,0,1,2.06,3.25m29.57-24.39c-4.45,17-9.54,27.23-19.53,38.11a4.55,4.55,0,0,1-3.26-2.79,63,63,0,0,0,7.26-9.4,98.66,98.66,0,0,1-10.8-26.09,9.55,9.55,0,0,1,2.86-.4,12.79,12.79,0,0,1,2.05.17A103.05,103.05,0,0,0,234,46.58l.45.86c.12-.29.29-.52.4-.8A91.25,91.25,0,0,0,242.51,25a11.84,11.84,0,0,1,1.88-.17,7.91,7.91,0,0,1,2.8.57"/><path class="cls-2" d="M42.92,53.29H17.28L36.61,19.9,55.94,53.29l5.64,9.94H73.22L36.61,0,0,63.23H47.42Z"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -20,6 +20,13 @@ module.exports = {
'8xl': '1920px', '8xl': '1920px',
}, },
colors: { colors: {
transparent: "transparent",
black: "#000",
white: "#fff",
agility: "#222",
primary: 'var(--primary)', primary: 'var(--primary)',
'primary-2': 'var(--primary-2)', 'primary-2': 'var(--primary-2)',
secondary: 'var(--secondary)', secondary: 'var(--secondary)',

View File

@ -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" resolved "https://registry.yarnpkg.com/react-fast-marquee/-/react-fast-marquee-1.1.3.tgz#8f1f397c64258bdee0e915147d503828ab74d695"
integrity sha512-DIfrpWMgIHEoEPWKYzs5dnV5ZSMuu0+4ddRG4qB6Ee2zDi5LuPAGc1gnOceG8j8tvnuSrdkaqYYQwLZ61VzU5w== 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: react-is@16.13.1, react-is@^16.8.1:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"