refactor: raise Gitako out of document body

This commit is contained in:
EnixCoda 2022-07-12 01:15:48 +08:00
parent 8f0e4a9ccb
commit 98a67381db
6 changed files with 46 additions and 96 deletions

View file

@ -127,8 +127,11 @@ export function SideBar() {
collapsed: !shouldShow,
})}
baseSize={baseSize}
// TODO: move sidebarToggleMode inside
onLeave={sidebarToggleMode === 'float' ? () => setShowSideBar(false) : undefined}
sizeVariableMountPoint={sidebarToggleMode === 'persistent' ? document.body : undefined}
sizeVariableMountPoint={
sidebarToggleMode === 'persistent' ? DOMHelper.gitakoDescriptionTarget : undefined
}
>
<div className={'gitako-side-bar-body'}>
<div

View file

@ -7,6 +7,7 @@ import { cx } from 'utils/cx'
import { setCSSVariable } from 'utils/DOMHelper'
import * as features from 'utils/features'
import { detectBrowser } from 'utils/general'
import { useOnPJAXDone } from 'utils/hooks/usePJAX'
import { ResizeState } from 'utils/hooks/useResizeHandler'
import { useConditionalHook } from '../utils/hooks/useConditionalHook'
@ -53,7 +54,6 @@ export function SideBarBodyWrapper({
const safeSize = getSafeSize(size, width)
if (safeSize !== size) setSize(safeSize)
}, [width, size])
const bodyWrapperRef = React.useRef<HTMLDivElement | null>(null)
useDebounce(() => configContext.onChange({ sideBarWidth: size }), 100, [size])
const applySizeToCSSVariables = React.useCallback(function apply(
@ -66,13 +66,6 @@ export function SideBarBodyWrapper({
sizeVariableMountPoint ? `${size}px` : undefined,
sizeVariableMountPoint,
)
if (bodyWrapperRef.current)
setCSSVariable(
'--gitako-width',
sizeVariableMountPoint ? undefined : `${size}px`,
bodyWrapperRef.current,
)
},
[])
@ -95,9 +88,15 @@ export function SideBarBodyWrapper({
}
}, [width, sizeVariableMountPoint, applySizeToCSSVariables])
const applyLatestSizeToCSSVariables = React.useCallback(
() => applySizeToCSSVariables(sizeVariableMountPoint, size),
[sizeVariableMountPoint, size],
)
React.useEffect(() => {
applySizeToCSSVariables(sizeVariableMountPoint, size)
}, [sizeVariableMountPoint, size, applySizeToCSSVariables])
applyLatestSizeToCSSVariables()
}, [applyLatestSizeToCSSVariables])
useOnPJAXDone(applyLatestSizeToCSSVariables)
const onMouseLeave = React.useCallback(
<E extends HTMLElement>(e: React.MouseEvent<E>) => {
@ -112,11 +111,10 @@ export function SideBarBodyWrapper({
blockLeaveRef.current = state === 'resizing'
}, [])
const defaultSideBarWidth = React.useMemo(() => getDefaultConfigs().sideBarWidth, []);
const defaultSideBarWidth = React.useMemo(() => getDefaultConfigs().sideBarWidth, [])
return (
<div
ref={bodyWrapperRef}
className={cx('gitako-side-bar-body-wrapper', className)}
style={{ height: heightForSafari }}
onMouseLeave={onMouseLeave}

View file

@ -1,7 +1,7 @@
import { Gitako } from 'components/Gitako'
import * as React from 'react'
import { createRoot } from 'react-dom/client'
import { insertSideBarMountPoint, persistGitakoElements } from 'utils/DOMHelper'
import { insertSideBarMountPoint } from 'utils/DOMHelper'
import './content.scss'
if (document.readyState === 'loading') {
@ -12,7 +12,6 @@ if (document.readyState === 'loading') {
async function init() {
await injectStyles(browser.runtime.getURL('content.css'))
persistGitakoElements()
createRoot(insertSideBarMountPoint()).render(<Gitako />)
}

View file

@ -99,7 +99,7 @@ $minimal-z-index: max(
mask-position: center;
}
.#{$name}-ready {
[data-#{$name}-ready='true'] {
// github
// code folding start
.blob-wrapper table .blob-num {
@ -232,16 +232,18 @@ $minimal-z-index: max(
}
}
.with-gitako-spacing {
@media screen {
margin-left: var(--gitako-width);
}
html[data-with-gitako-spacing='true'] {
body {
@media screen {
margin-left: var(--gitako-width);
}
// gitee
&.git-project {
width: auto; // shrink width
.site-content {
min-width: 1040px;
// gitee
&.git-project {
width: auto; // shrink width
.site-content {
min-width: 1040px;
}
}
}
}
@ -425,6 +427,7 @@ $minimal-z-index: max(
display: flex;
flex-direction: column;
background: var(--color-bg-subtle);
font-size: 14px;
.octicon-wrapper {
display: inline-block;
@ -638,6 +641,7 @@ $minimal-z-index: max(
overflow: hidden;
text-overflow: ellipsis;
align-items: center;
font-size: 14px;
}
&:not(:hover) {

View file

@ -3,33 +3,24 @@
*/
export const rootElementID = 'gitako-root'
export function setGitakoBodyClass(className: string, enable: boolean) {
const classList = document.body.classList
if (enable) classList.add(className)
else classList.remove(className)
}
export const gitakoDescriptionTarget = document.documentElement
/**
* when gitako is ready, make page's header narrower
* or cancel it
*/
export function markGitakoReadyState(ready: boolean) {
const readyClassName = 'gitako-ready'
return setGitakoBodyClass(readyClassName, ready)
const readyAttributeName = 'data-gitako-ready'
return gitakoDescriptionTarget.setAttribute(readyAttributeName, `${ready}`)
}
/**
* if should show gitako, then move body right to make space for showing gitako
* otherwise, hide the space
*/
export const bodySpacingClassName = 'with-gitako-spacing'
export const spacingAttributeName = 'data-with-gitako-spacing'
export function setBodyIndent(shouldShowGitako: boolean) {
if (shouldShowGitako) {
document.body.classList.add(bodySpacingClassName)
} else {
document.body.classList.remove(bodySpacingClassName)
}
gitakoDescriptionTarget.setAttribute(spacingAttributeName, `${shouldShowGitako}`)
}
export function $(selector: string): HTMLElement | null
@ -56,20 +47,20 @@ export function $(selector: string, existCallback?: any, otherwise?: any) {
/**
* DOM Structure after calling the `insert*MountPoint` functions
*
* <html>
* <body>
* <div id={rootElementID}>
* <div id={sidebarMountPointID}>
* </div>
* <div id={logoMountPointID}>
* </div>
* </div>
* </body>
* </html>
* <html>
* <body>
* </body>
* <div id={rootElementID}>
* <div id={sidebarMountPointID}>
* </div>
* <div id={logoMountPointID}>
* </div>
* </div>
* </html>
*/
const mountPointContainer = document.documentElement
export function insertMountPoint() {
const mountPointContainer = document.body // TODO: when replace this, refactor root of `$`
return $(formatID(rootElementID), undefined, () => {
const element = document.createElement('div')
element.setAttribute('id', rootElementID)
@ -186,46 +177,3 @@ export function formatClass(className: string) {
export function parseIntFromElement(e: HTMLElement): number {
return parseInt((e.innerText || '').replace(/[^0-9]/g, ''))
}
/**
* 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(mountPointElement = insertMountPoint()) {
mountPointElement.setAttribute('data-turbo-permanent', '')
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 = [bodySpacingClassName]
for (const cssClass of cssClassesNeedToMigrate) {
if (removedBody.classList.contains(cssClass)) addedBody.classList.add(cssClass)
}
// move gitako elements
if (!addedBody.contains(mountPointElement)) addedBody.appendChild(mountPointElement)
if (removedBody.contains(mountPointElement)) removedBody.removeChild(mountPointElement)
}
}
function findBodyElement(addedNodes: NodeList) {
return Array.from(addedNodes).find(addedNode => addedNode instanceof HTMLBodyElement) as
| HTMLBodyElement
| undefined
}
})
observer.observe(document.documentElement, {
childList: true,
})
}

View file

@ -58,9 +58,7 @@ export const loadWithPJAX = (url: string, element: HTMLElement) => {
export function useOnPJAXDone(callback: () => void) {
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)
useEvent('turbo:render', callback, document)
}
export function useRedirectedEvents(