diff --git a/src/components/layout/header/HeaderContent.tsx b/src/components/layout/header/HeaderContent.tsx
index 41c50ce425..2430c987e5 100644
--- a/src/components/layout/header/HeaderContent.tsx
+++ b/src/components/layout/header/HeaderContent.tsx
@@ -46,10 +46,7 @@ const AnimatedMenu: Component = ({ children }) => {
)
}
-function ForDesktop({
- className,
- ...props
-}: React.HTMLAttributes
) {
+const ForDesktop: Component = ({ className }) => {
const mouseX = useMotionValue(0)
const mouseY = useMotionValue(0)
const radius = useMotionValue(0)
@@ -63,12 +60,11 @@ function ForDesktop({
[mouseX, mouseY, radius],
)
- const pathname = usePathname()
-
const { config: headerMenuConfig } = useHeaderConfig()
return (
-
+
)
}
+const HeaderMenuItem = memo<{
+ section: IHeaderMenu
+}>(({ section }) => {
+ const pathname = usePathname()
+ const href = section.path
+ const isActive = pathname === href || pathname.startsWith(`${href}/`)
+ return (
+
+
+
+
+ {section.icon}
+
+ {section.title}
+
+
+
+ )
+})
const MenuPopover: Component<{
subMenu: IHeaderMenu['subMenu']
}> = memo(({ children, subMenu }) => {
@@ -151,7 +152,7 @@ const MenuPopover: Component<{
)
})
-function NavItem({
+function AnimatedItem({
href,
children,
className,
diff --git a/src/components/layout/header/HeaderDataConfigureProvider.tsx b/src/components/layout/header/HeaderDataConfigureProvider.tsx
index 2dd17d82ea..8fefb33a4a 100644
--- a/src/components/layout/header/HeaderDataConfigureProvider.tsx
+++ b/src/components/layout/header/HeaderDataConfigureProvider.tsx
@@ -3,7 +3,7 @@
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
-import { useAggregation } from '~/hooks/data/use-aggregation'
+import { useAggregationQuery } from '~/hooks/data/use-aggregation'
import { cloneDeep } from '~/lib/_'
import { headerMenuConfig as baseHeaderMenuConfig } from './config'
@@ -14,7 +14,7 @@ const HeaderMenuConfigContext = createContext({
export const useHeaderConfig = () => useContext(HeaderMenuConfigContext)
export const HeaderDataConfigureProvider: Component = ({ children }) => {
- const { data } = useAggregation()
+ const { data } = useAggregationQuery()
const [headerMenuConfig, setHeaderMenuConfig] = useState(baseHeaderMenuConfig)
useEffect(() => {
diff --git a/src/components/layout/header/SiteOwnerAvatar.tsx b/src/components/layout/header/SiteOwnerAvatar.tsx
new file mode 100644
index 0000000000..b57f505887
--- /dev/null
+++ b/src/components/layout/header/SiteOwnerAvatar.tsx
@@ -0,0 +1,22 @@
+'use client'
+
+import Image from 'next/image'
+
+import { useAggregationSelector } from '~/providers/root/aggregation-data-provider'
+
+export const SiteOwnerAvatar = () => {
+ const avatar = useAggregationSelector((data) => data.user.avatar)
+
+ if (!avatar) return
+ return (
+
+
+
+ )
+}
diff --git a/src/hooks/data/use-aggregation.ts b/src/hooks/data/use-aggregation.ts
index 1b67ecf1c8..47304dec96 100644
--- a/src/hooks/data/use-aggregation.ts
+++ b/src/hooks/data/use-aggregation.ts
@@ -1,9 +1,14 @@
import { useQuery } from '@tanstack/react-query'
+import type { AggregateRoot } from '@mx-space/api-client'
+import type { UseQueryOptions } from '@tanstack/react-query'
import { aggregation } from '../../queries/definition/aggregation'
-export const useAggregation = () => {
+export const useAggregationQuery = (
+ options?: UseQueryOptions,
+) => {
return useQuery({
...aggregation.root(),
+ ...options,
})
}
diff --git a/src/providers/root/aggregation-data-provider.tsx b/src/providers/root/aggregation-data-provider.tsx
new file mode 100644
index 0000000000..cdd17f0d3a
--- /dev/null
+++ b/src/providers/root/aggregation-data-provider.tsx
@@ -0,0 +1,41 @@
+import { useCallback, useEffect } from 'react'
+import { atom, useAtomValue } from 'jotai'
+import { selectAtom } from 'jotai/utils'
+import type { AggregateRoot } from '@mx-space/api-client'
+import type { FC, PropsWithChildren } from 'react'
+
+import { useAggregationQuery } from '~/hooks/data/use-aggregation'
+import { jotaiStore } from '~/lib/store'
+
+const aggregationDataAtom = atom(null)
+
+export const AggregationProvider: FC = ({ children }) => {
+ const { data } = useAggregationQuery()
+
+ useEffect(() => {
+ if (!data) return
+ jotaiStore.set(aggregationDataAtom, data)
+ }, [data])
+
+ return children
+}
+
+/**
+ * Not recommended to use
+ */
+export const useAggregationData = () => useAtomValue(aggregationDataAtom)
+
+export const useAggregationSelector = (
+ selector: (atomValue: AggregateRoot) => T,
+ deps: any[] = [],
+): T | null =>
+ useAtomValue(
+ // @ts-expect-error
+ selectAtom(
+ aggregationDataAtom,
+ useCallback(
+ (atomValue) => (!atomValue ? null : selector(atomValue)),
+ deps,
+ ),
+ ),
+ )
diff --git a/src/providers/root/index.tsx b/src/providers/root/index.tsx
index e341442356..98341e94f5 100644
--- a/src/providers/root/index.tsx
+++ b/src/providers/root/index.tsx
@@ -5,6 +5,7 @@ import React from 'react'
import { ThemeProvider } from 'next-themes'
import type { PropsWithChildren } from 'react'
+import { AggregationProvider } from './aggregation-data-provider'
import { DebugProvider } from './debug-provider'
import { JotaiStoreProvider } from './jotai-provider'
import { PageScrollInfoProvider } from './page-scroll-info-provider'
@@ -23,6 +24,7 @@ const contexts: JSX.Element[] = [
,
,
,
+ ,
,
,
,