Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"raw-loader": "^4.0.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-modal": "^3.14.4",
"url-loader": "^4.1.1"
},
"devDependencies": {
Expand Down
46 changes: 46 additions & 0 deletions src/components/Modal.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.mainContainer {
max-width: 420px;
margin: auto;
background: #f9fbfc;
padding: 2em;
border-radius: 6px;
box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.25);
display: flex;
flex-direction: column;
justify-self: center;
align-self: center;
}

html[data-theme="dark"] .mainContainer {
background-color: var(--ifm-background-surface-color);
}

.buttonsContainer {
flex: auto;
text-align: right;
font-weight: 600;
margin-top: 1rem;
}

.buttonsContainer > * {
margin-right: 1rem;
}

.overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.75);
z-index: 999;
display: flex;
}

html[data-theme="dark"] .overlay {
background-color: rgba(0, 0, 0, 0.75);
}

input[type="checkbox"] {
margin-right: 0.5rem;
}
129 changes: 129 additions & 0 deletions src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React, { useEffect } from "react"
import ModalCmp from "react-modal"
import { DONT_SHOW_PRIVATE_GITHUB_WARNING_KEY } from "../theme/Root"
import styles from "./Modal.module.css"

interface ModalProps {
externalLink: string
showModal: boolean
children?: React.ReactNode
shouldCloseOnEsc?: boolean
shouldAcceptOnEnter?: boolean
shouldCloseOnOverlayClick?: boolean
handleCancelRequest: () => void
handleAcceptRequest?: () => void
}

export const idOfNoticeLink = "notice"

if (typeof window !== "undefined") {
ModalCmp.setAppElement("body")
}

export const SubscriptionNoticeModal: React.FC<ModalProps> = ({
externalLink,
showModal,
shouldCloseOnEsc = true,
shouldAcceptOnEnter = false,
shouldCloseOnOverlayClick = true,
handleCancelRequest,
handleAcceptRequest,
}) => {
const onRequestClose = () => {
// If the user checked to never see this notice but subsequently cancels we will disregard their selection. We will
// only stop showing this notice if they check the box and then proceed to GitHub
Comment on lines +33 to +34
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that this is intentional - Is there a particular reason for disregarding it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can discuss this quickly next time we speak - but for the purpose of this PR we do want to have that behavior. It's a slightly better user experience as it applies your wishes only after you've chosen to follow the link forward. Otherwise you can get into a s situation where you dind't mean to dismiss the thing and never see it again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏾

if(window.localStorage.getItem(DONT_SHOW_PRIVATE_GITHUB_WARNING_KEY)) {
window.localStorage.removeItem(DONT_SHOW_PRIVATE_GITHUB_WARNING_KEY)
}

handleCancelRequest()
}

const gitHubRepoName = externalLink.match(
/https:\/\/github.com\/gruntwork-io\/(.*?)\/.*/
)

// function to check if there's any active button (focus on the button) to avoid conflicts with shouldAcceptOnEnter property
const checkIfAnyActiveButton = () => {
const activeElement = document.activeElement
if (activeElement && activeElement.tagName.toLowerCase() === "button") {
return true
}
return false
}

useEffect(() => {
if (showModal) {
document.body.style.overflow = "hidden"
}
const timer = setTimeout(() => {
if (!showModal) {
document.body.style.overflow = "unset"
}
}, 300)
return () => clearTimeout(timer)
}, [showModal])

useEffect(() => {
const listener = (e: any) => {
const code = e.key
if (
code === "Enter" &&
handleAcceptRequest &&
shouldAcceptOnEnter &&
showModal &&
!checkIfAnyActiveButton()
) {
e.preventDefault()
handleAcceptRequest()
}
}
document.addEventListener("keydown", listener, false)
return () => {
document.removeEventListener("keydown", listener, false)
}
})

const setDontWarnMe = (event) => {
event.stopPropagation()
if(!window.localStorage.getItem(DONT_SHOW_PRIVATE_GITHUB_WARNING_KEY)) {
window.localStorage.setItem(DONT_SHOW_PRIVATE_GITHUB_WARNING_KEY, "true")
} else {
window.localStorage.removeItem(DONT_SHOW_PRIVATE_GITHUB_WARNING_KEY)
}
}

return (
<ModalCmp
isOpen={showModal}
preventScroll={true}
onRequestClose={onRequestClose}
shouldCloseOnEsc={shouldCloseOnEsc}
shouldCloseOnOverlayClick={shouldCloseOnOverlayClick}
closeTimeoutMS={0}
className={styles.mainContainer}
overlayClassName={styles.overlay}
>
<h2>For Subscribers Only</h2>
<p>
This link leads to the private{" "}
{gitHubRepoName && gitHubRepoName.length >= 1 && (
<code>{gitHubRepoName[1]}</code>
)}{" "}
repository visible only to subscribers; everyone else will see a 404.
</p>
<div>
<input type="checkbox" onClick={setDontWarnMe} />
<label>Don't warn me again</label>
</div>
<div className={styles.buttonsContainer}>
<a onClick={() => onRequestClose()} href="#">
Cancel
</a>
<a id={idOfNoticeLink} href={externalLink} target="_blank">
Continue to GitHub
</a>
</div>
</ModalCmp>
)
}
19 changes: 19 additions & 0 deletions src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,25 @@ html[data-theme="dark"] .menu__link--sublist {
border-left: 2px solid var(--ifm-color-primary);
}

/* BUTTONS */
.link-button {
display: inline-block;
padding: 0.5rem 2rem;
background: #5849a6;
color: white;
font-weight: 600;
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
border-radius: 100vh;
transition: 0.2s ease-in-out;
}

.link-button:hover {
color: white;
text-decoration: none;
filter: brightness(1.1);
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.25);
}

/* FOOTER */

/* --ifm-footer-background-color doesn't appear to work */
Expand Down
59 changes: 59 additions & 0 deletions src/theme/Root.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useState, useEffect } from "react"
import {
SubscriptionNoticeModal,
idOfNoticeLink,
} from "/src/components/Modal.tsx"

const gruntworkRepos = "https://github.com/gruntwork-io"

export const DONT_SHOW_PRIVATE_GITHUB_WARNING_KEY = "dontWarnGitHubLinks"

function Root({ children }) {
const [displaySubscriberNotice, setDisplaySubscriberNotice] = useState(false)
const [externalLink, setExternalLink] = useState("")

useEffect(() => {
const listener = (event) => {
if (event.target.id === idOfNoticeLink) {
setDisplaySubscriberNotice(false)
return
}
const dontWarn = window.localStorage.getItem(
DONT_SHOW_PRIVATE_GITHUB_WARNING_KEY
)

if (dontWarn) {
setDisplaySubscriberNotice(false)
return
}

if (event.target.href && event.target.href.includes(gruntworkRepos)) {
event.preventDefault()
console.log
setExternalLink(event.target.href)
setDisplaySubscriberNotice(true)
}
}

window.addEventListener("click", listener)

// use-effect cleanup
return () => window.removeEventListener("click", listener)
}, [])

return (
<>
<SubscriptionNoticeModal
showModal={displaySubscriberNotice}
externalLink={externalLink}
handleCancelRequest={() => {
setDisplaySubscriberNotice(false)
setExternalLink("")
}}
/>
{children}
</>
)
}

export default Root
24 changes: 23 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5048,6 +5048,11 @@ execa@^5.0.0:
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"

exenv@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=

express@^4.17.1:
version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
Expand Down Expand Up @@ -7927,7 +7932,7 @@ react-json-view@^1.21.3:
react-lifecycles-compat "^3.0.4"
react-textarea-autosize "^8.3.2"

react-lifecycles-compat@^3.0.4:
react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
Expand All @@ -7939,6 +7944,16 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1:
dependencies:
"@babel/runtime" "^7.10.3"

react-modal@^3.14.4:
version "3.14.4"
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.14.4.tgz#2ca7e8e9a180955e5c9508c228b73167c1e6f6a3"
integrity sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg==
dependencies:
exenv "^1.2.0"
prop-types "^15.7.2"
react-lifecycles-compat "^3.0.0"
warning "^4.0.3"

react-router-config@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988"
Expand Down Expand Up @@ -9382,6 +9397,13 @@ wait-on@^6.0.0:
minimist "^1.2.5"
rxjs "^7.1.0"

warning@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"

watchpack@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce"
Expand Down