Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial static indicator #7682

Merged
merged 10 commits into from Jul 3, 2019
7 changes: 7 additions & 0 deletions packages/next-server/lib/router/router.ts
Expand Up @@ -304,6 +304,13 @@ export default class Router implements BaseRouter {
this.changeState(method, url, as, options)
const hash = window.location.hash.substring(1)

if (process.env.NODE_ENV !== 'production') {
const appComp: any = this.components['/_app'].Component
;(window as any).next.isPrerendered =
appComp.getInitialProps === appComp.origGetInitialProps &&
!routeInfo.Component.getInitialProps
}

// @ts-ignore pathname is always defined
this.set(route, pathname, query, as, { ...routeInfo, hash })

Expand Down
2 changes: 1 addition & 1 deletion packages/next/client/dev/dev-build-watcher.js
Expand Up @@ -6,7 +6,7 @@ export default function initializeBuildWatcher () {
// Make sure container is fixed and on a high zIndex so it shows
shadowHost.style.position = 'fixed'
shadowHost.style.bottom = '10px'
shadowHost.style.right = '10px'
shadowHost.style.right = '20px'
shadowHost.style.width = 0
shadowHost.style.height = 0
shadowHost.style.zIndex = 99999
Expand Down
152 changes: 152 additions & 0 deletions packages/next/client/dev/prerender-indicator.js
@@ -0,0 +1,152 @@
import Router from '../router'

export default function initializeBuildWatcher () {
const shadowHost = document.createElement('div')
shadowHost.id = '__next-prerender-indicator'
// Make sure container is fixed and on a high zIndex so it shows
shadowHost.style.position = 'fixed'
shadowHost.style.bottom = '20px'
shadowHost.style.right = '10px'
shadowHost.style.width = 0
shadowHost.style.height = 0
shadowHost.style.zIndex = 99998
shadowHost.style.transition = 'all 100ms ease'
shadowHost.title = 'Click to hide for page'

document.body.appendChild(shadowHost)

let shadowRoot
let prefix = ''

if (shadowHost.attachShadow) {
shadowRoot = shadowHost.attachShadow({ mode: 'open' })
} else {
// If attachShadow is undefined then the browser does not support
// the Shadow DOM, we need to prefix all the names so there
// will be no conflicts
shadowRoot = shadowHost
prefix = '__next-prerender-indicator-'
}

// Container
const container = createContainer(prefix)
shadowRoot.appendChild(container)

// CSS
const css = createCss(prefix)
shadowRoot.appendChild(css)

// State
let isVisible = window.__NEXT_DATA__.nextExport

function updateContainer () {
if (isVisible) {
container.classList.add(`${prefix}visible`)
} else {
container.classList.remove(`${prefix}visible`)
}
}

shadowHost.addEventListener('click', () => (shadowHost.style.opacity = 0))
shadowHost.addEventListener('mouseenter', () => {
container.classList.add(`${prefix}expanded`)
})
shadowHost.addEventListener('mouseleave', () => {
container.classList.remove(`${prefix}expanded`)
})

Router.events.on('routeChangeComplete', () => {
isVisible = window.next.isPrerendered
shadowHost.style.opacity = 1
updateContainer()
})
updateContainer()
}

function createContainer (prefix) {
const container = document.createElement('div')
container.id = `${prefix}container`
container.innerHTML = `
<div id="${prefix}icon-wrapper">
<svg width="15" height="20" viewBox="0 0 60 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M36 3L30.74 41H8L36 3Z" fill="black"/>
<path d="M25 77L30.26 39H53L25 77Z" fill="black"/>
<path d="M13.5 33.5L53 39L47.5 46.5L7 41.25L13.5 33.5Z" fill="black"/>
</svg>
Prerendered Page
</div>
`

return container
}

function createCss (prefix) {
const css = document.createElement('style')
css.textContent = `
#${prefix}container {
position: absolute;
bottom: 10px;
right: 15px;
width: 15px;
height: 23px;
overflow: hidden;

border-radius: 3px;
background: #fff;
color: #000;
font: initial;
cursor: pointer;
letter-spacing: initial;
text-shadow: initial;
text-transform: initial;
visibility: initial;
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;

padding: 4px 2px;
align-items: center;
box-shadow: 0 11px 40px 0 rgba(0, 0, 0, 0.25), 0 2px 10px 0 rgba(0, 0, 0, 0.12);

display: none;
opacity: 0;
transition: opacity 0.1s ease, bottom 0.1s ease, width 0.3s ease;
animation: ${prefix}fade-in 0.1s ease-in-out;
}

#${prefix}icon-wrapper {
width: 140px;
height: 20px;
display: flex;
flex-shrink: 0;
align-items: center;
}

#${prefix}icon-wrapper svg {
flex-shrink: 0;
margin-right: 3px;
}

#${prefix}container.${prefix}expanded {
width: 140px;
}

#${prefix}container.${prefix}visible {
display: flex;
bottom: 10px;
opacity: 1;
}

@keyframes ${prefix}fade-in {
from {
bottom: 0px;
opacity: 0;
}
to {
bottom: 10px;
opacity: 1;
}
}
`

return css
}
2 changes: 2 additions & 0 deletions packages/next/client/next-dev.js
Expand Up @@ -3,6 +3,7 @@ import EventSourcePolyfill from './dev/event-source-polyfill'
import initOnDemandEntries from './dev/on-demand-entries-client'
import initWebpackHMR from './dev/webpack-hot-middleware-client'
import initializeBuildWatcher from './dev/dev-build-watcher'
import initializePrerenderIndicator from './dev/prerender-indicator'

// Temporary workaround for the issue described here:
// https://github.com/zeit/next.js/issues/3775#issuecomment-407438123
Expand All @@ -27,6 +28,7 @@ initNext({ webpackHMR })
.then(emitter => {
initOnDemandEntries({ assetPrefix: prefix })
initializeBuildWatcher()
initializePrerenderIndicator()

let lastScroll

Expand Down