mirror of
https://github.com/Athou/commafeed.git
synced 2026-10-09 13:54:51 +00:00
move handlers in Layout because they actually only apply to the reader pages
This commit is contained in:
@@ -4,21 +4,16 @@ import { MantineProvider, v8CssVariablesResolver } from "@mantine/core"
|
|||||||
import { ModalsProvider } from "@mantine/modals"
|
import { ModalsProvider } from "@mantine/modals"
|
||||||
import { Notifications } from "@mantine/notifications"
|
import { Notifications } from "@mantine/notifications"
|
||||||
import type React from "react"
|
import type React from "react"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect } from "react"
|
||||||
import { HashRouter, Navigate, Route, Routes, useNavigate } from "react-router-dom"
|
import { HashRouter, Navigate, Route, Routes, useNavigate } from "react-router-dom"
|
||||||
import Tinycon from "tinycon"
|
|
||||||
import { Constants } from "@/app/constants"
|
import { Constants } from "@/app/constants"
|
||||||
import { redirectTo } from "@/app/redirect/slice"
|
import { redirectTo } from "@/app/redirect/slice"
|
||||||
import { redirectToInitialSetup } from "@/app/redirect/thunks"
|
import { redirectToInitialSetup } from "@/app/redirect/thunks"
|
||||||
import { reloadServerInfos } from "@/app/server/thunks"
|
import { reloadServerInfos } from "@/app/server/thunks"
|
||||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||||
import { categoryUnreadCount } from "@/app/utils"
|
|
||||||
import { DisablePullToRefresh } from "@/components/DisablePullToRefresh"
|
|
||||||
import { ErrorBoundary } from "@/components/ErrorBoundary"
|
import { ErrorBoundary } from "@/components/ErrorBoundary"
|
||||||
import { Header } from "@/components/header/Header"
|
import { Header } from "@/components/header/Header"
|
||||||
import { Tree } from "@/components/sidebar/Tree"
|
import { Tree } from "@/components/sidebar/Tree"
|
||||||
import { useAppLoading } from "@/hooks/useAppLoading"
|
|
||||||
import { useBrowserExtension } from "@/hooks/useBrowserExtension"
|
|
||||||
import { useI18n } from "@/i18n"
|
import { useI18n } from "@/i18n"
|
||||||
import { AdminUsersPage } from "@/pages/admin/AdminUsersPage"
|
import { AdminUsersPage } from "@/pages/admin/AdminUsersPage"
|
||||||
import { MetricsPage } from "@/pages/admin/MetricsPage"
|
import { MetricsPage } from "@/pages/admin/MetricsPage"
|
||||||
@@ -146,83 +141,8 @@ function RedirectHandler() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function UnreadCountTitleHandler({
|
|
||||||
enabled,
|
|
||||||
}: Readonly<{
|
|
||||||
enabled?: boolean
|
|
||||||
}>) {
|
|
||||||
const root = useAppSelector(state => state.tree.rootCategory)
|
|
||||||
const unreadCount = categoryUnreadCount(root)
|
|
||||||
return <title>{enabled && unreadCount > 0 ? `(${unreadCount}) CommaFeed` : "CommaFeed"}</title>
|
|
||||||
}
|
|
||||||
|
|
||||||
function UnreadCountFaviconHandler({ enabled }: { enabled?: boolean }) {
|
|
||||||
const root = useAppSelector(state => state.tree.rootCategory)
|
|
||||||
const unreadCount = categoryUnreadCount(root)
|
|
||||||
useEffect(() => {
|
|
||||||
if (enabled && unreadCount > 0) {
|
|
||||||
Tinycon.setBubble(unreadCount)
|
|
||||||
} else {
|
|
||||||
Tinycon.reset()
|
|
||||||
}
|
|
||||||
}, [unreadCount, enabled])
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
function BrowserExtensionBadgeUnreadCountHandler() {
|
|
||||||
const root = useAppSelector(state => state.tree.rootCategory)
|
|
||||||
const { setBadgeUnreadCount } = useBrowserExtension()
|
|
||||||
useEffect(() => {
|
|
||||||
if (!root) return
|
|
||||||
const unreadCount = categoryUnreadCount(root)
|
|
||||||
setBadgeUnreadCount(unreadCount)
|
|
||||||
}, [root, setBadgeUnreadCount])
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
function CustomJsHandler() {
|
|
||||||
const [scriptLoaded, setScriptLoaded] = useState(false)
|
|
||||||
const { loading } = useAppLoading()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (scriptLoaded || loading) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const script = document.createElement("script")
|
|
||||||
script.src = "custom_js.js"
|
|
||||||
script.async = true
|
|
||||||
document.body.appendChild(script)
|
|
||||||
|
|
||||||
setScriptLoaded(true)
|
|
||||||
|
|
||||||
return () => script.remove()
|
|
||||||
}, [scriptLoaded, loading])
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
function CustomCssHandler() {
|
|
||||||
useEffect(() => {
|
|
||||||
const link = document.createElement("link")
|
|
||||||
link.rel = "stylesheet"
|
|
||||||
link.type = "text/css"
|
|
||||||
link.href = "custom_css.css"
|
|
||||||
document.head.appendChild(link)
|
|
||||||
|
|
||||||
return () => link.remove()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
useI18n()
|
useI18n()
|
||||||
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
|
|
||||||
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
|
|
||||||
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
|
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -231,13 +151,6 @@ export function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Providers>
|
<Providers>
|
||||||
<UnreadCountTitleHandler enabled={unreadCountTitle} />
|
|
||||||
<UnreadCountFaviconHandler enabled={unreadCountFavicon} />
|
|
||||||
<BrowserExtensionBadgeUnreadCountHandler />
|
|
||||||
<CustomJsHandler />
|
|
||||||
<CustomCssHandler />
|
|
||||||
<DisablePullToRefresh enabled={disablePullToRefresh} />
|
|
||||||
|
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<InitialSetupHandler />
|
<InitialSetupHandler />
|
||||||
<RedirectHandler />
|
<RedirectHandler />
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { msg } from "@lingui/core/macro"
|
import { msg } from "@lingui/core/macro"
|
||||||
import { ActionIcon, AppShell, Box, Center, Group, ScrollArea, Title, useMantineTheme } from "@mantine/core"
|
import { ActionIcon, AppShell, Box, Center, Group, ScrollArea, Title, useMantineTheme } from "@mantine/core"
|
||||||
import { type ReactNode, type RefObject, Suspense, useEffect, useRef } from "react"
|
import { type ReactNode, type RefObject, Suspense, useEffect, useRef, useState } from "react"
|
||||||
import Draggable from "react-draggable"
|
import Draggable from "react-draggable"
|
||||||
import { TbMenu2, TbPlus, TbX } from "react-icons/tb"
|
import { TbMenu2, TbPlus, TbX } from "react-icons/tb"
|
||||||
import { Outlet } from "react-router-dom"
|
import { Outlet } from "react-router-dom"
|
||||||
import { useSwipeable } from "react-swipeable"
|
import { useSwipeable } from "react-swipeable"
|
||||||
|
import Tinycon from "tinycon"
|
||||||
import { Constants } from "@/app/constants"
|
import { Constants } from "@/app/constants"
|
||||||
import { redirectToAdd, redirectToRootCategory } from "@/app/redirect/thunks"
|
import { redirectToAdd, redirectToRootCategory } from "@/app/redirect/thunks"
|
||||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||||
@@ -12,8 +13,10 @@ import { setMobileMenuOpen } from "@/app/tree/slice"
|
|||||||
import { reloadTree } from "@/app/tree/thunks"
|
import { reloadTree } from "@/app/tree/thunks"
|
||||||
import { setSidebarWidth } from "@/app/user/slice"
|
import { setSidebarWidth } from "@/app/user/slice"
|
||||||
import { reloadProfile, reloadSettings, reloadTags } from "@/app/user/thunks"
|
import { reloadProfile, reloadSettings, reloadTags } from "@/app/user/thunks"
|
||||||
|
import { categoryUnreadCount } from "@/app/utils"
|
||||||
import { ActionButton } from "@/components/ActionButton"
|
import { ActionButton } from "@/components/ActionButton"
|
||||||
import { AnnouncementDialog } from "@/components/AnnouncementDialog"
|
import { AnnouncementDialog } from "@/components/AnnouncementDialog"
|
||||||
|
import { DisablePullToRefresh } from "@/components/DisablePullToRefresh"
|
||||||
import { Loader } from "@/components/Loader"
|
import { Loader } from "@/components/Loader"
|
||||||
import { Logo } from "@/components/Logo"
|
import { Logo } from "@/components/Logo"
|
||||||
import { MarkAllAsReadConfirmationDialog } from "@/components/MarkAllAsReadConfirmationDialog"
|
import { MarkAllAsReadConfirmationDialog } from "@/components/MarkAllAsReadConfirmationDialog"
|
||||||
@@ -51,6 +54,78 @@ function LogoAndTitle() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function UnreadCountTitleHandler({
|
||||||
|
enabled,
|
||||||
|
}: Readonly<{
|
||||||
|
enabled?: boolean
|
||||||
|
}>) {
|
||||||
|
const root = useAppSelector(state => state.tree.rootCategory)
|
||||||
|
const unreadCount = categoryUnreadCount(root)
|
||||||
|
return <title>{enabled && unreadCount > 0 ? `(${unreadCount}) CommaFeed` : "CommaFeed"}</title>
|
||||||
|
}
|
||||||
|
|
||||||
|
function UnreadCountFaviconHandler({ enabled }: { enabled?: boolean }) {
|
||||||
|
const root = useAppSelector(state => state.tree.rootCategory)
|
||||||
|
const unreadCount = categoryUnreadCount(root)
|
||||||
|
useEffect(() => {
|
||||||
|
if (enabled && unreadCount > 0) {
|
||||||
|
Tinycon.setBubble(unreadCount)
|
||||||
|
} else {
|
||||||
|
Tinycon.reset()
|
||||||
|
}
|
||||||
|
}, [unreadCount, enabled])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function BrowserExtensionBadgeUnreadCountHandler() {
|
||||||
|
const root = useAppSelector(state => state.tree.rootCategory)
|
||||||
|
const { setBadgeUnreadCount } = useBrowserExtension()
|
||||||
|
useEffect(() => {
|
||||||
|
if (!root) return
|
||||||
|
const unreadCount = categoryUnreadCount(root)
|
||||||
|
setBadgeUnreadCount(unreadCount)
|
||||||
|
}, [root, setBadgeUnreadCount])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function CustomJsHandler() {
|
||||||
|
const [scriptLoaded, setScriptLoaded] = useState(false)
|
||||||
|
const { loading } = useAppLoading()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (scriptLoaded || loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const script = document.createElement("script")
|
||||||
|
script.src = "custom_js.js"
|
||||||
|
script.async = true
|
||||||
|
document.body.appendChild(script)
|
||||||
|
|
||||||
|
setScriptLoaded(true)
|
||||||
|
|
||||||
|
return () => script.remove()
|
||||||
|
}, [scriptLoaded, loading])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function CustomCssHandler() {
|
||||||
|
useEffect(() => {
|
||||||
|
const link = document.createElement("link")
|
||||||
|
link.rel = "stylesheet"
|
||||||
|
link.type = "text/css"
|
||||||
|
link.href = "custom_css.css"
|
||||||
|
document.head.appendChild(link)
|
||||||
|
|
||||||
|
return () => link.remove()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const useStyles = tss
|
const useStyles = tss
|
||||||
.withParams<{
|
.withParams<{
|
||||||
sidebarWidth: number
|
sidebarWidth: number
|
||||||
@@ -75,6 +150,9 @@ export default function Layout(props: Readonly<LayoutProps>) {
|
|||||||
const draggableSeparator = useRef<HTMLDivElement>(null)
|
const draggableSeparator = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
const { loading } = useAppLoading()
|
const { loading } = useAppLoading()
|
||||||
|
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
|
||||||
|
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
|
||||||
|
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
|
||||||
const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen)
|
const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen)
|
||||||
const webSocketConnected = useAppSelector(state => state.server.webSocketConnected)
|
const webSocketConnected = useAppSelector(state => state.server.webSocketConnected)
|
||||||
const treeReloadInterval = useAppSelector(state => state.server.serverInfos?.treeReloadInterval)
|
const treeReloadInterval = useAppSelector(state => state.server.serverInfos?.treeReloadInterval)
|
||||||
@@ -173,6 +251,13 @@ export default function Layout(props: Readonly<LayoutProps>) {
|
|||||||
|
|
||||||
if (loading) return <LoadingPage />
|
if (loading) return <LoadingPage />
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<UnreadCountTitleHandler enabled={unreadCountTitle} />
|
||||||
|
<UnreadCountFaviconHandler enabled={unreadCountFavicon} />
|
||||||
|
<BrowserExtensionBadgeUnreadCountHandler />
|
||||||
|
<CustomJsHandler />
|
||||||
|
<CustomCssHandler />
|
||||||
|
<DisablePullToRefresh enabled={disablePullToRefresh} />
|
||||||
<Box {...swipeHandlers}>
|
<Box {...swipeHandlers}>
|
||||||
<AppShell
|
<AppShell
|
||||||
header={{ height: Constants.layout.headerHeight, collapsed: headerInFooter }}
|
header={{ height: Constants.layout.headerHeight, collapsed: headerInFooter }}
|
||||||
@@ -229,5 +314,6 @@ export default function Layout(props: Readonly<LayoutProps>) {
|
|||||||
</AppShell.Main>
|
</AppShell.Main>
|
||||||
</AppShell>
|
</AppShell>
|
||||||
</Box>
|
</Box>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user