diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx
index 8d23b6a..ebee564 100644
--- a/src/components/SideBar.tsx
+++ b/src/components/SideBar.tsx
@@ -63,7 +63,7 @@ export function SideBar() {
: intelligentToggle,
)
const shouldShow = $shouldShow.value
- React.useEffect(() => {
+ const toggleBodyIndent = React.useCallback(() => {
if (sidebarToggleMode === 'persistent') {
DOMHelper.setBodyIndent(shouldShow)
} else {
@@ -75,6 +75,12 @@ export function SideBar() {
}
}, [shouldShow, sidebarToggleMode])
+ React.useEffect(() => {
+ toggleBodyIndent()
+ }, [toggleBodyIndent])
+
+ useOnPJAXDone(toggleBodyIndent)
+
// Save expand state on toggle if auto expand is off
React.useEffect(() => {
if (intelligentToggle !== null) {
diff --git a/src/content.tsx b/src/content.tsx
index cc11087..71cb78e 100644
--- a/src/content.tsx
+++ b/src/content.tsx
@@ -4,6 +4,11 @@ import { addMiddleware } from 'driver/connect'
import { platform } from 'platforms'
import * as React from 'react'
import * as ReactDOM from 'react-dom'
+import {
+ insertLogoMountPoint,
+ insertSideBarMountPoint,
+ persistGitakoElements
+} from 'utils/DOMHelper'
import './content.scss'
if (platform.resolvePartialMetaData()) {
@@ -18,8 +23,9 @@ if (platform.resolvePartialMetaData()) {
async function init() {
await injectStyles(browser.runtime.getURL('content.css'))
- const SideBarElement = document.createElement('div')
- document.body.appendChild(SideBarElement)
+ const SideBarElement = insertSideBarMountPoint()
+ const logoElement = insertLogoMountPoint()
+ persistGitakoElements(SideBarElement, logoElement)
ReactDOM.render(, SideBarElement)
}
diff --git a/src/platforms/GitHub/index.ts b/src/platforms/GitHub/index.ts
index c9a8d15..c7d5592 100644
--- a/src/platforms/GitHub/index.ts
+++ b/src/platforms/GitHub/index.ts
@@ -112,6 +112,7 @@ const pathSHAMap = new Map()
const pjaxContainerSelector = ['#repo-content-pjax-container', '#js-repo-pjax-container'].find(
selector => document.querySelector(selector),
)
+const turboContainerId = 'repo-content-turbo-frame'
export const GitHub: Platform = {
isEnterprise,
@@ -213,6 +214,7 @@ export const GitHub: Platform = {
if (configRef.pjaxMode === 'native' && (!options?.node || options.node.type === 'blob'))
return {
'data-pjax': pjaxContainerSelector,
+ 'data-turbo-frame': turboContainerId,
onClick() {
/* Overwriting default onClick */
},
diff --git a/src/utils/DOMHelper.ts b/src/utils/DOMHelper.ts
index b369b46..3b7eff6 100644
--- a/src/utils/DOMHelper.ts
+++ b/src/utils/DOMHelper.ts
@@ -36,17 +36,17 @@ export function setBodyIndent(shouldShowGitako: boolean) {
}
export function $(selector: string): HTMLElement | null
-export function $(selector: string, existCallback: (element: HTMLElement) => T1): T1
+export function $(selector: string, existCallback: (element: HTMLElement) => T1): T1 | null
export function $(
selector: string,
existCallback: (element: HTMLElement) => T1,
otherwise: () => T2,
-): T1 | T2
+): T1 | T2 | null
export function $(
selector: string,
existCallback: undefined | null,
otherwise: () => T2,
-): HTMLElement | null | T2
+): HTMLElement | T2
export function $(selector: string, existCallback?: any, otherwise?: any) {
const element = document.querySelector(selector)
if (element) {
@@ -55,6 +55,15 @@ export function $(selector: string, existCallback?: any, otherwise?: any) {
return otherwise ? otherwise() : null
}
+export function insertSideBarMountPoint() {
+ const mountPointID = 'gitako-mount-point-wrapper'
+ const sideBarElement = document.createElement('div')
+ sideBarElement.setAttribute('data-turbo-permanent', '')
+ sideBarElement.setAttribute('id', mountPointID)
+ document.body.appendChild(sideBarElement)
+ return sideBarElement
+}
+
/**
* add the logo element into DOM
*/
@@ -64,6 +73,7 @@ export function insertLogoMountPoint() {
return $(logoSelector, undefined, function createLogoMountPoint() {
const logoMountElement = document.createElement('div')
logoMountElement.setAttribute('id', logoID)
+ logoMountElement.setAttribute('data-turbo-permanent', '')
document.body.appendChild(logoMountElement)
return logoMountElement
})
@@ -142,3 +152,46 @@ export function setCSSVariable(name: string, value: string | undefined, element:
if (value === undefined) element.style.removeProperty(name)
else element.style.setProperty(name, value)
}
+
+/**
+ * Unlike the good-old-PJAX-time, now GitHub replaces whole body element after redirecting using turbo.
+ * If move Gitako mount point from `body` to `html`, Gitako style would break because it inherits style from GitHub body.
+ * The temporary solution is recovery Gitako elements once the body is removed.
+ */
+export function persistGitakoElements(SideBarElement: HTMLElement, logoElement: HTMLElement) {
+ const observer = new MutationObserver(mutations => {
+ for (const { addedNodes, removedNodes } of mutations) {
+ const [addedBody, removedBody] = [addedNodes, removedNodes].map(findBodyElement)
+ if (addedBody && removedBody) {
+ // hard-coded list due to limited time
+ // TODO: refactor in a better practice
+
+ // migrate gitako attributes, e.g. class
+ const propertiesNeedToMigrate = ['--gitako-width']
+ for (const property of propertiesNeedToMigrate) {
+ const oldValue = removedBody.style.getPropertyValue(property)
+ if (oldValue) addedBody.style.setProperty(property, oldValue)
+ }
+ const cssClassesNeedToMigrate = ['with-gitako-spacing']
+ for (const cssClass of cssClassesNeedToMigrate) {
+ if (removedBody.classList.contains(cssClass)) addedBody.classList.add(cssClass)
+ }
+
+ // move gitako elements
+ if (!addedBody.contains(SideBarElement)) addedBody.appendChild(SideBarElement)
+ if (removedBody.contains(SideBarElement)) removedBody.removeChild(SideBarElement)
+ if (!addedBody.contains(logoElement)) addedBody.appendChild(logoElement)
+ if (removedBody.contains(logoElement)) removedBody.removeChild(logoElement)
+ }
+ }
+
+ function findBodyElement(addedNodes: NodeList) {
+ return Array.from(addedNodes).find(addedNode => addedNode instanceof HTMLBodyElement) as
+ | HTMLBodyElement
+ | undefined
+ }
+ })
+ observer.observe(document.documentElement, {
+ childList: true,
+ })
+}
diff --git a/src/utils/hooks/usePJAX.ts b/src/utils/hooks/usePJAX.ts
index ba06191..80e37bc 100644
--- a/src/utils/hooks/usePJAX.ts
+++ b/src/utils/hooks/usePJAX.ts
@@ -4,6 +4,8 @@ import { platform } from 'platforms'
import * as React from 'react'
import { useEvent } from 'react-use'
+// TODO: rename PJAX
+
const config: Config = {
areas: [
// github
@@ -53,7 +55,10 @@ export const loadWithPJAX = (url: string, element: HTMLElement) => {
}
export function useOnPJAXDone(callback: () => void) {
- useEvent('pjax:end', callback, document)
+ useEvent('pjax:end', callback, document) // legacy support
+ // 'turbo:render' should be the best timing but GitHub has attached a mutation observer on body to block that
+ // TODO: fire at turbo:render
+ useEvent('turbo:load', callback, document)
}
export function useRedirectedEvents(