fix: recover attributes removed by GitHub

fixes #263
This commit is contained in:
EnixCoda 2022-12-24 22:43:42 +08:00
parent 3a0680b53d
commit aeb6b6341c
3 changed files with 79 additions and 11 deletions

View file

@ -183,8 +183,12 @@ function useFocusSidebarOnExpand(shouldExpand: boolean) {
function useMarkGitakoReadyState() {
React.useEffect(() => {
const detach = DOMHelper.attachStickyGitakoReadyState()
DOMHelper.markGitakoReadyState(true)
return () => DOMHelper.markGitakoReadyState(false)
return () => {
detach()
DOMHelper.markGitakoReadyState(false)
}
}, [])
}
@ -199,9 +203,13 @@ function useLogoContainerElement() {
function useUpdateBodyIndentOnStateUpdate(shouldExpand: boolean) {
const { sidebarToggleMode } = useConfigs().value
React.useEffect(() => {
if (sidebarToggleMode === 'persistent' && shouldExpand) {
DOMHelper.setBodyIndent(true)
return () => DOMHelper.setBodyIndent(false)
if (!(sidebarToggleMode === 'persistent' && shouldExpand)) return
const detach = DOMHelper.attachStickyBodyIndent()
DOMHelper.setBodyIndent(true)
return () => {
detach()
DOMHelper.setBodyIndent(false)
}
}, [sidebarToggleMode, shouldExpand])
}

View file

@ -1,6 +1,6 @@
import { useConfigs } from 'containers/ConfigsContext'
import * as React from 'react'
import { useDebounce, useWindowSize } from 'react-use'
import { useDebounce, useLatest, useWindowSize } from 'react-use'
import { getDefaultConfigs } from 'utils/config/helper'
import * as DOMHelper from 'utils/DOMHelper'
import { useAfterRedirect } from 'utils/hooks/useFastRedirect'
@ -27,6 +27,12 @@ function useSidebarWidth() {
React.useLayoutEffect(() => DOMHelper.setGitakoWidthCSSVariable(width), [width])
const widthRef = useLatest(width)
React.useEffect(() => {
const detach = DOMHelper.attachStickyGitakoWidthCSSVariable(() => widthRef.current)
return () => detach()
}, [widthRef])
// Keep variable when directing from PR to repo home via meta bar
useAfterRedirect(React.useCallback(() => DOMHelper.setGitakoWidthCSSVariable(width), [width]))

View file

@ -7,20 +7,69 @@ import { $ } from './$'
export const rootElementID = 'gitako-root'
export const gitakoDescriptionTarget = document.documentElement
// Some custom attributes added to GitHub html would be removed by GitHub when some events happen
function attachStickyAttribute(
target: Node,
shouldAttach: (mutation: MutationRecord) => boolean,
attach: (mutation: MutationRecord) => void,
mutationOptions?: MutationObserverInit,
) {
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) if (shouldAttach(mutation)) attach(mutation)
})
observer.observe(target, {
attributeOldValue: true,
attributes: true,
...mutationOptions,
})
return () => observer.disconnect()
}
export const attachStickyDataAttribute = (
target: HTMLElement,
attributeName: string,
attach: (mutation: MutationRecord) => void,
) =>
attachStickyAttribute(target, () => !target.getAttribute(attributeName), attach, {
attributeFilter: [attributeName],
})
export const attachStickyStyle = (
target: HTMLElement,
styleName: string,
attach: (mutation: MutationRecord) => void,
) =>
attachStickyAttribute(
target,
() => !target.style.getPropertyValue(styleName), // `''` if not exist
attach,
{ attributeFilter: ['style'] },
)
/**
* when gitako is ready, make page's header narrower
* or cancel it
* when gitako is ready, attach attribute to activate CSS selectors
* e.g. make page's header narrower on pin sidebar
*/
const readyDataAttributeName = 'data-gitako-ready'
export const attachStickyGitakoReadyState = () =>
attachStickyDataAttribute(gitakoDescriptionTarget, readyDataAttributeName, ({ oldValue }) =>
markGitakoReadyState(oldValue === 'true'),
)
export function markGitakoReadyState(ready: boolean) {
const readyAttributeName = 'data-gitako-ready'
return gitakoDescriptionTarget.setAttribute(readyAttributeName, `${ready}`)
return gitakoDescriptionTarget.setAttribute(readyDataAttributeName, `${ready}`)
}
/**
* if should show gitako, then move body right to make space for showing gitako
* otherwise, hide the space
*/
export const spacingAttributeName = 'data-with-gitako-spacing'
const spacingAttributeName = 'data-with-gitako-spacing'
export const attachStickyBodyIndent = () =>
attachStickyDataAttribute(gitakoDescriptionTarget, spacingAttributeName, ({ oldValue }) =>
setBodyIndent(oldValue === 'true'),
)
export function setBodyIndent(shouldShowGitako: boolean) {
gitakoDescriptionTarget.setAttribute(spacingAttributeName, `${shouldShowGitako}`)
}
@ -122,8 +171,13 @@ export function setCSSVariable(name: string, value: string | undefined, element:
else element.style.setProperty(name, value)
}
const gitakoWidthVariable = '--gitako-width'
export const attachStickyGitakoWidthCSSVariable = (getLatestSize: () => number) =>
attachStickyStyle(gitakoDescriptionTarget, gitakoWidthVariable, () => {
setGitakoWidthCSSVariable(getLatestSize())
})
export const setGitakoWidthCSSVariable = (size: number) => {
setCSSVariable('--gitako-width', `${size}px`, gitakoDescriptionTarget)
setCSSVariable(gitakoWidthVariable, `${size}px`, gitakoDescriptionTarget)
}
export function formatID(id: string) {