mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 14:13:43 +01:00
[web] Add compilation indicator favicon (#25990)
* Import changes from Hackathon https://github.com/overleaf/internal/pull/24501 * Update compile status: allow errors * Update favicons. Use the ones from Figma * Optimize and reuse path from favicon.svg * Clear status favicon after 5s on active tab * Rename hook from useCompileNotification to useStatusFavicon * Add tests * Revert changes to favicon.svg * Query favicon on document.head GitOrigin-RevId: 3972b1981abaf6c80273e0ed5b1bc05eb51bd689
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
} from '@/features/ide-redesign/utils/new-editor-utils'
|
||||
import EditorSurvey from '../editor-survey'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import { useStatusFavicon } from '@/features/ide-react/hooks/use-status-favicon'
|
||||
|
||||
const MainLayoutNew = lazy(
|
||||
() => import('@/features/ide-redesign/components/main-layout')
|
||||
@@ -30,6 +31,7 @@ export default function IdePage() {
|
||||
useEditingSessionHeartbeat() // send a batched event when user is active
|
||||
useRegisterUserActivity() // record activity and ensure connection when user is active
|
||||
useHasLintingError() // pass editor:lint hasLintingError to the compiler
|
||||
useStatusFavicon() // update the favicon based on the compile status
|
||||
|
||||
const newEditor = useIsNewEditorEnabled()
|
||||
const canAccessNewEditor = canUseNewEditor()
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
|
||||
import { useEffect, useState } from 'react'
|
||||
import usePreviousValue from '@/shared/hooks/use-previous-value'
|
||||
|
||||
const RESET_AFTER_MS = 5_000
|
||||
|
||||
const COMPILE_ICONS = {
|
||||
ERROR: '/favicon-error.svg',
|
||||
COMPILING: '/favicon-compiling.svg',
|
||||
COMPILED: '/favicon-compiled.svg',
|
||||
UNCOMPILED: '/favicon.svg',
|
||||
}
|
||||
|
||||
type CompileStatus = keyof typeof COMPILE_ICONS
|
||||
|
||||
const useCompileStatus = (): CompileStatus => {
|
||||
const compileContext = useCompileContext()
|
||||
if (compileContext.uncompiled) return 'UNCOMPILED'
|
||||
if (compileContext.compiling) return 'COMPILING'
|
||||
if (compileContext.error) return 'ERROR'
|
||||
return 'COMPILED'
|
||||
}
|
||||
|
||||
const removeFavicon = () => {
|
||||
const existingFavicons = document.head.querySelectorAll(
|
||||
"link[rel='icon']"
|
||||
) as NodeListOf<HTMLLinkElement>
|
||||
existingFavicons.forEach(favicon => {
|
||||
if (favicon.href.endsWith('.svg')) favicon.parentNode?.removeChild(favicon)
|
||||
})
|
||||
}
|
||||
|
||||
const updateFavicon = (status: CompileStatus = 'UNCOMPILED') => {
|
||||
removeFavicon()
|
||||
const linkElement = document.createElement('link')
|
||||
linkElement.rel = 'icon'
|
||||
linkElement.href = COMPILE_ICONS[status]
|
||||
linkElement.type = 'image/svg+xml'
|
||||
linkElement.setAttribute('data-compile-status', 'true')
|
||||
document.head.appendChild(linkElement)
|
||||
}
|
||||
|
||||
const isActive = () => !document.hidden
|
||||
|
||||
const useIsWindowActive = () => {
|
||||
const [isWindowActive, setIsWindowActive] = useState(isActive())
|
||||
useEffect(() => {
|
||||
const handleVisibilityChange = () => setIsWindowActive(isActive())
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange)
|
||||
return () => {
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
||||
}
|
||||
}, [])
|
||||
return isWindowActive
|
||||
}
|
||||
|
||||
export const useStatusFavicon = () => {
|
||||
const compileStatus = useCompileStatus()
|
||||
const previousCompileStatus = usePreviousValue(compileStatus)
|
||||
const isWindowActive = useIsWindowActive()
|
||||
|
||||
useEffect(() => {
|
||||
if (previousCompileStatus !== compileStatus) {
|
||||
return updateFavicon(compileStatus)
|
||||
}
|
||||
|
||||
if (
|
||||
isWindowActive &&
|
||||
(compileStatus === 'COMPILED' || compileStatus === 'ERROR')
|
||||
) {
|
||||
const timeout = setTimeout(updateFavicon, RESET_AFTER_MS)
|
||||
return () => clearTimeout(timeout)
|
||||
}
|
||||
}, [compileStatus, isWindowActive, previousCompileStatus])
|
||||
}
|
||||
Reference in New Issue
Block a user