Skip to content

feat: upgrading to nextjs app router #169

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
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
272 changes: 195 additions & 77 deletions custom-implementation/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,118 +1,236 @@
import './main.css'
import '@devrev/marketing-shared-components/dist/cjs/index.css'

import ReactDOM from 'react-dom'

import ReactDOM from 'react-dom/client'
import React from 'react'

import Header from './components/header'
import Footer from './components/footer'
import { ThemeSwitch } from './components/theme-switch'

import { getPageData } from './modules/sanity/utils'

const FERN_CONTENT_WRAPPER_ID = 'fern-header-content-wrapper'
const DEVREV_CONTENT_WRAPPER_ID = 'devrev-header-content-wrapper'

const FERN_HEADER_CONTAINER_ID = 'fern-header'

const render = async () => {
console.log('Starting render function')
/*
* This is a where we try to make async data call.
*/

const data = await getPageData()
console.log('Page data fetched:', data ? 'success' : 'failed')

// Check if we're in a browser environment
if (typeof window === 'undefined') {
console.log('Not in browser environment, exiting render')
return
}

console.log('Looking for sidenav element')
const sidenav = document.querySelector('button.fern-search-bar')
?.parentElement as HTMLElement
console.log('Sidenav found:', sidenav ? 'yes' : 'no')

const theme = document.getElementsByTagName('html')[0].getAttribute('class')
const theme = document.documentElement.getAttribute('class')
console.log('Current theme:', theme)

if (!document.getElementById('theme-switch')) {
// Add theme switch to sidenav
if (!document.getElementById('theme-switch') && sidenav) {
console.log('Adding theme switch to sidenav')
const wrapper = document.createElement('div')
wrapper.setAttribute('id', 'theme-switch')
sidenav.appendChild(wrapper)
ReactDOM.render(React.createElement(ThemeSwitch), wrapper)
const root = ReactDOM.createRoot(wrapper)
root.render(React.createElement(ThemeSwitch))
console.log('Theme switch added')
} else {
console.log('Theme switch already exists or sidenav not found')
}

const fernHeaderId = document.getElementById(FERN_CONTENT_WRAPPER_ID)
const devrevHeaderId = document.getElementById(DEVREV_CONTENT_WRAPPER_ID)

if (!fernHeaderId && !devrevHeaderId) {
// Main Container
const fernHeaderContainer = document.createElement('div')
fernHeaderContainer.setAttribute('id', FERN_HEADER_CONTAINER_ID)

// Fern Header
const fernContentWrapper = document.createElement('div')
fernContentWrapper.setAttribute('id', FERN_CONTENT_WRAPPER_ID)

const devrevContentWrapper = document.createElement('div')
devrevContentWrapper.setAttribute('id', DEVREV_CONTENT_WRAPPER_ID)

// Get existing fern-header element and its children
const mainHeaderWrapper = document.getElementById(FERN_HEADER_CONTAINER_ID)

if (mainHeaderWrapper) {
// Move all children to the wrapper
while (mainHeaderWrapper.firstChild) {
fernContentWrapper.appendChild(mainHeaderWrapper.firstChild)
// Find the existing Fern header
console.log('Looking for Fern header')
const existingFernHeader = document.getElementById(FERN_HEADER_CONTAINER_ID)
console.log('Fern header found:', existingFernHeader ? 'yes' : 'no')

if (existingFernHeader) {
// Check if our custom wrappers already exist
let fernContentWrapper = document.getElementById(FERN_CONTENT_WRAPPER_ID)
let devrevContentWrapper = document.getElementById(DEVREV_CONTENT_WRAPPER_ID)
console.log('Existing wrappers found:', {
fernWrapper: fernContentWrapper ? 'yes' : 'no',
devrevWrapper: devrevContentWrapper ? 'yes' : 'no'
})

// If wrappers don't exist, create them
if (!fernContentWrapper) {
console.log('Creating Fern content wrapper')
fernContentWrapper = document.createElement('div')
fernContentWrapper.setAttribute('id', FERN_CONTENT_WRAPPER_ID)

// Move all existing children to the Fern wrapper
console.log('Moving existing children to Fern wrapper')
while (existingFernHeader.firstChild) {
fernContentWrapper.appendChild(existingFernHeader.firstChild)
}

existingFernHeader.appendChild(fernContentWrapper)
console.log('Fern content wrapper created and populated')
}

fernHeaderContainer.appendChild(fernContentWrapper)
fernHeaderContainer.appendChild(devrevContentWrapper)

// Insert the new container where the original fern-header was
if (mainHeaderWrapper) {
mainHeaderWrapper.replaceWith(fernHeaderContainer)

if (!devrevContentWrapper) {
console.log('Creating DevRev content wrapper')
devrevContentWrapper = document.createElement('div')
devrevContentWrapper.setAttribute('id', DEVREV_CONTENT_WRAPPER_ID)
existingFernHeader.appendChild(devrevContentWrapper)

// Render our custom header in the DevRev wrapper
console.log('Rendering custom header in DevRev wrapper')
const headerRoot = ReactDOM.createRoot(devrevContentWrapper)

// Remove display style forcing for production
// fernContentWrapper.style.display = 'block'
// devrevContentWrapper.style.display = 'block'

// Pass header data to the component
headerRoot.render(
React.createElement(Header, {
version: theme === 'dark' ? 'light' : 'dark',
...data.header
})
)
console.log('Custom header rendered')
} else {
document.body.appendChild(fernHeaderContainer)
// Update the header with current theme if it already exists
console.log('Updating existing header with current theme')
const headerRoot = ReactDOM.createRoot(devrevContentWrapper)
headerRoot.render(
React.createElement(Header, {
version: theme === 'dark' ? 'light' : 'dark',
...data.header
})
)
}

ReactDOM.render(

// Make sure the header is visible
console.log('Making header visible')
existingFernHeader.style.display = 'block'
} else {
// If Fern header doesn't exist yet, create it
console.log('Fern header not found, creating it')
const newHeader = document.createElement('div')
newHeader.setAttribute('id', FERN_HEADER_CONTAINER_ID)
document.body.insertBefore(newHeader, document.body.firstChild)

// Create DevRev content wrapper
const devrevContentWrapper = document.createElement('div')
devrevContentWrapper.setAttribute('id', DEVREV_CONTENT_WRAPPER_ID)
newHeader.appendChild(devrevContentWrapper)

// Render our custom header
console.log('Rendering custom header in new element')
const headerRoot = ReactDOM.createRoot(devrevContentWrapper)
headerRoot.render(
React.createElement(Header, {
...data.header,
version: theme == 'dark' ? 'light' : 'dark',
}),
devrevContentWrapper,
() => {
// Once the header component is loaded, make it visible
const header = document.getElementById(FERN_HEADER_CONTAINER_ID)
if (header) header.style.display = 'block'
}
version: theme === 'dark' ? 'light' : 'dark',
...data.header
})
)
console.log('Custom header created and rendered')
}

ReactDOM.render(
React.createElement(Footer, { ...data.footer }),
document.getElementById('fern-footer'),
() => {
// Handle footer rendering
console.log('Looking for footer element')
const footerElement = document.getElementById('fern-footer')
console.log('Footer element found:', footerElement ? 'yes' : 'no')

if (footerElement) {
// Check if footer is already rendered
const hasChildren = footerElement.hasChildNodes()
console.log('Footer already has children:', hasChildren ? 'yes' : 'no')

if (!hasChildren) {
console.log('Rendering footer component')
const footerRoot = ReactDOM.createRoot(footerElement)
footerRoot.render(React.createElement(Footer, { ...data.footer }))

// Once the footer component is loaded, make it visible
const footer = document.getElementById('fern-footer')
if (footer) footer.style.display = 'block'
},
)
console.log('Making footer visible')
footerElement.style.display = 'block'
}
} else {
// Create footer if it doesn't exist
console.log('Creating new footer element')
const newFooter = document.createElement('div')
newFooter.setAttribute('id', 'fern-footer')
document.body.appendChild(newFooter)

console.log('Rendering footer in new element')
const footerRoot = ReactDOM.createRoot(newFooter)
footerRoot.render(React.createElement(Footer, { ...data.footer }))
newFooter.style.display = 'block'
console.log('Footer created and rendered')
}

console.log('Render function completed')
}

let observations = 0
document.addEventListener('DOMContentLoaded', async () => {
console.log('DOMContentLoaded')
await render()
new MutationObserver(async (e, o) => {
await render()
for (const item of e) {
if (item.target instanceof HTMLElement) {
const target = item.target
if (target.id === 'fern-header' || target.id === 'fern-footer') {
if (observations < 3) {
// react hydration will trigger a mutation event
observations++
} else {
o.disconnect()
}
break
// For Next.js App Router compatibility
const initApp = () => {
console.log('Initializing app')
if (typeof window !== 'undefined') {
console.log('Browser environment detected')

// Function to attempt rendering multiple times
const attemptRender = (attempts = 0, maxAttempts = 5) => {
console.log(`Render attempt ${attempts + 1} of ${maxAttempts}`)
render().then(() => {
// Check if header and footer are properly rendered
const header = document.getElementById(DEVREV_CONTENT_WRAPPER_ID)
const footer = document.getElementById('fern-footer')
const headerRendered = header && header.children.length > 0
const footerRendered = footer && footer.children.length > 0

console.log('Render check:', {
headerRendered: headerRendered ? 'yes' : 'no',
footerRendered: footerRendered ? 'yes' : 'no'
})

// If not rendered properly and we haven't reached max attempts, try again
if ((!headerRendered || !footerRendered) && attempts < maxAttempts - 1) {
console.log('Components not fully rendered, trying again in 500ms')
setTimeout(() => attemptRender(attempts + 1, maxAttempts), 500)
} else if (attempts >= maxAttempts - 1) {
console.log('Max render attempts reached')
} else {
console.log('Components successfully rendered')
}
}
})
}

// Check if the DOM is already loaded
if (document.readyState === 'loading') {
console.log('DOM still loading, adding DOMContentLoaded listener')
document.addEventListener('DOMContentLoaded', () => {
console.log('DOMContentLoaded event fired')
attemptRender()
})
} else {
// DOM already loaded, render immediately
console.log('DOM already loaded, rendering immediately')
attemptRender()
}
}).observe(document.body, { childList: true, subtree: true })
})

// Also add a window load event to ensure everything is rendered
window.addEventListener('load', () => {
console.log('Window load event fired')
render()
})
} else {
console.log('Not in browser environment, skipping initialization')
}
}

// Initialize the app
console.log('Starting application initialization')
initApp()
5 changes: 5 additions & 0 deletions fern/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ js:
strategy: beforeInteractive


layout:
searchbar-placement: sidebar
tabs-placement: sidebar
disable-header: true

typography:
bodyFont:
name: SF Pro
Expand Down
Loading