mirror of
https://github.com/linsa-io/linsa.git
synced 2026-01-12 12:20:23 +01:00
fix: eager loading for nested topic
This commit is contained in:
@@ -7,8 +7,8 @@ import { Link } from "@tanstack/react-router"
|
|||||||
import { getFeatureFlag } from "~/actions"
|
import { getFeatureFlag } from "~/actions"
|
||||||
|
|
||||||
export const JournalSection: React.FC = () => {
|
export const JournalSection: React.FC = () => {
|
||||||
const { me } = useAccount()
|
const { me } = useAccount({ root: { journalEntries: [{}] } })
|
||||||
const journalEntries = me?.root?.journalEntries
|
const journalEntries = me?.root.journalEntries
|
||||||
|
|
||||||
const [, setIsFetching] = useState(false)
|
const [, setIsFetching] = useState(false)
|
||||||
const [isFeatureActive, setIsFeatureActive] = useState(false)
|
const [isFeatureActive, setIsFeatureActive] = useState(false)
|
||||||
|
|||||||
@@ -3,25 +3,16 @@ import { useAccount } from "@/lib/providers/jazz-provider"
|
|||||||
import { NavItem } from "~/components/custom/nav-item"
|
import { NavItem } from "~/components/custom/nav-item"
|
||||||
|
|
||||||
export const LinkCollection: React.FC = () => {
|
export const LinkCollection: React.FC = () => {
|
||||||
const { me } = useAccount({
|
const { me } = useAccount()
|
||||||
root: {
|
|
||||||
personalLinks: [],
|
|
||||||
personalPages: [],
|
|
||||||
topicsWantToLearn: [],
|
|
||||||
topicsLearning: [],
|
|
||||||
topicsLearned: [],
|
|
||||||
tasks: [],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const linkCount = me?.root.personalLinks?.length || 0
|
const linkCount = me?.root?.personalLinks?.length || 0
|
||||||
const pageCount = me?.root.personalPages?.length || 0
|
const pageCount = me?.root?.personalPages?.length || 0
|
||||||
const taskCount = me?.root.tasks?.length || 0
|
const taskCount = me?.root?.tasks?.length || 0
|
||||||
|
|
||||||
const topicCount =
|
const topicCount =
|
||||||
(me?.root.topicsWantToLearn?.length || 0) +
|
(me?.root?.topicsWantToLearn?.length || 0) +
|
||||||
(me?.root.topicsLearning?.length || 0) +
|
(me?.root?.topicsLearning?.length || 0) +
|
||||||
(me?.root.topicsLearned?.length || 0)
|
(me?.root?.topicsLearned?.length || 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-px py-2">
|
<div className="flex flex-col gap-px py-2">
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
import * as React from "react"
|
|
||||||
import { Link } from "@tanstack/react-router"
|
|
||||||
import { useAccount } from "@/lib/providers/jazz-provider"
|
|
||||||
import { cn } from "@/lib/utils"
|
|
||||||
import { PersonalLinkLists } from "@/lib/schema/personal-link"
|
|
||||||
import { LearningStateValue } from "~/lib/constants"
|
|
||||||
import { LaIcon } from "~/components/custom/la-icon"
|
|
||||||
|
|
||||||
export const LinkSection: React.FC = () => {
|
|
||||||
const { me } = useAccount({ root: { personalLinks: [] } })
|
|
||||||
|
|
||||||
if (!me) return null
|
|
||||||
|
|
||||||
const linkCount = me.root.personalLinks?.length || 0
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col gap-px">
|
|
||||||
<LinkSectionHeader linkCount={linkCount} />
|
|
||||||
<LinkList personalLinks={me.root.personalLinks} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LinkSectionHeaderProps {
|
|
||||||
linkCount: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const LinkSectionHeader: React.FC<LinkSectionHeaderProps> = ({ linkCount }) => {
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
to="/links"
|
|
||||||
className={cn(
|
|
||||||
"flex h-[30px] items-center gap-px rounded-md px-2 text-sm font-medium hover:bg-[var(--item-hover)] focus-visible:outline-none focus-visible:ring-0",
|
|
||||||
)}
|
|
||||||
activeProps={{
|
|
||||||
className:
|
|
||||||
"bg-[var(--item-active)] data-[status='active']:hover:bg-[var(--item-active)]",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ isActive }) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="flex items-center gap-1.5">
|
|
||||||
<LaIcon name="Link" className="" />
|
|
||||||
<span>Links</span>
|
|
||||||
</div>
|
|
||||||
<span className="flex flex-auto"></span>
|
|
||||||
{linkCount > 0 && (
|
|
||||||
<span
|
|
||||||
className={cn("font-mono text-muted-foreground", {
|
|
||||||
"text-foreground": isActive,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{linkCount}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LinkListProps {
|
|
||||||
personalLinks: PersonalLinkLists
|
|
||||||
}
|
|
||||||
|
|
||||||
const LinkList: React.FC<LinkListProps> = ({ personalLinks }) => {
|
|
||||||
const linkStates: LearningStateValue[] = [
|
|
||||||
"wantToLearn",
|
|
||||||
"learning",
|
|
||||||
"learned",
|
|
||||||
]
|
|
||||||
const linkLabels: Record<LearningStateValue, string> = {
|
|
||||||
wantToLearn: "To Learn",
|
|
||||||
learning: "Learning",
|
|
||||||
learned: "Learned",
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkCounts = linkStates.reduce(
|
|
||||||
(acc, state) => ({
|
|
||||||
...acc,
|
|
||||||
[state]: personalLinks.filter((link) => link?.learningState === state)
|
|
||||||
.length,
|
|
||||||
}),
|
|
||||||
{} as Record<LearningStateValue, number>,
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col gap-px">
|
|
||||||
{linkStates.map((state) => (
|
|
||||||
<LinkListItem
|
|
||||||
key={state}
|
|
||||||
label={linkLabels[state]}
|
|
||||||
state={state}
|
|
||||||
count={linkCounts[state]}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LinkListItemProps {
|
|
||||||
label: string
|
|
||||||
state: LearningStateValue
|
|
||||||
count: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const LinkListItem: React.FC<LinkListItemProps> = ({ label, state, count }) => (
|
|
||||||
<div className="relative flex min-w-0 flex-1">
|
|
||||||
<Link
|
|
||||||
to="/links"
|
|
||||||
search={{ state }}
|
|
||||||
className={cn(
|
|
||||||
"relative flex h-[30px] w-full items-center gap-2 rounded-md px-1.5 text-sm font-medium hover:bg-[var(--item-hover)]",
|
|
||||||
)}
|
|
||||||
activeProps={{
|
|
||||||
className:
|
|
||||||
"bg-[var(--item-active)] data-[status='active']:hover:bg-[var(--item-active)]",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ isActive }) => (
|
|
||||||
<>
|
|
||||||
<div className="flex max-w-full flex-1 items-center gap-1.5 truncate">
|
|
||||||
<p className="truncate">{label}</p>
|
|
||||||
</div>
|
|
||||||
{count > 0 && (
|
|
||||||
<span
|
|
||||||
className={cn("font-mono text-muted-foreground", {
|
|
||||||
"text-foreground": isActive,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{count}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { useAtom } from "jotai"
|
import { useAtom } from "jotai"
|
||||||
import { atomWithStorage } from "jotai/utils"
|
import { atomWithStorage } from "jotai/utils"
|
||||||
import { Link, useNavigate } from "@tanstack/react-router"
|
import { Link } from "@tanstack/react-router"
|
||||||
import { useAccount } from "@/lib/providers/jazz-provider"
|
import { useAccount } from "@/lib/providers/jazz-provider"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
@@ -49,9 +49,14 @@ const isExpandedAtom = atomWithStorage("isPageSectionExpanded", true)
|
|||||||
export const PageSection: React.FC = () => {
|
export const PageSection: React.FC = () => {
|
||||||
const { me } = useAccount({
|
const { me } = useAccount({
|
||||||
root: {
|
root: {
|
||||||
personalPages: [{}],
|
personalPages: [
|
||||||
|
{
|
||||||
|
topic: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const [sort] = useAtom(pageSortAtom)
|
const [sort] = useAtom(pageSortAtom)
|
||||||
const [show] = useAtom(pageShowAtom)
|
const [show] = useAtom(pageShowAtom)
|
||||||
const [isExpanded, setIsExpanded] = useAtom(isExpandedAtom)
|
const [isExpanded, setIsExpanded] = useAtom(isExpandedAtom)
|
||||||
@@ -163,23 +168,13 @@ const PageSectionHeader: React.FC<PageSectionHeaderProps> = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const NewPageButton: React.FC = () => {
|
const NewPageButton: React.FC = () => {
|
||||||
const { me } = useAccount()
|
|
||||||
const navigate = useNavigate()
|
|
||||||
const { newPage } = usePageActions()
|
const { newPage } = usePageActions()
|
||||||
|
|
||||||
const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
const page = newPage(me)
|
newPage()
|
||||||
|
|
||||||
if (page.id) {
|
|
||||||
navigate({
|
|
||||||
to: "/pages/$pageId",
|
|
||||||
params: { pageId: page.id },
|
|
||||||
replace: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -38,44 +38,48 @@ const useSidebarCollapse = (
|
|||||||
return [isCollapsed, setIsCollapsed]
|
return [isCollapsed, setIsCollapsed]
|
||||||
}
|
}
|
||||||
|
|
||||||
const SidebarItem: React.FC<SidebarItemProps> = React.memo(
|
const SidebarItem: React.FC<SidebarItemProps> = ({
|
||||||
({ label, url, icon, onClick, children }) => {
|
label,
|
||||||
const { pathname } = useLocation()
|
url,
|
||||||
const isActive = pathname === url
|
icon,
|
||||||
|
onClick,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const { pathname } = useLocation()
|
||||||
|
const isActive = pathname === url
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"group relative my-0.5 rounded-md",
|
"group relative my-0.5 rounded-md",
|
||||||
isActive ? "bg-secondary/80" : "hover:bg-secondary/40",
|
isActive ? "bg-secondary/80" : "hover:bg-secondary/40",
|
||||||
)}
|
)}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
className="flex h-8 grow items-center truncate rounded-md pl-1.5 pr-1 text-sm font-medium text-secondary-foreground"
|
||||||
|
to={url}
|
||||||
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
<Link
|
{icon && (
|
||||||
className="flex h-8 grow items-center truncate rounded-md pl-1.5 pr-1 text-sm font-medium text-secondary-foreground"
|
<span
|
||||||
to={url}
|
className={cn(
|
||||||
onClick={onClick}
|
"mr-2 size-4 text-primary/60 group-hover:text-primary",
|
||||||
>
|
{ "text-primary": isActive },
|
||||||
{icon && (
|
)}
|
||||||
<span
|
>
|
||||||
className={cn(
|
{icon}
|
||||||
"mr-2 size-4 text-primary/60 group-hover:text-primary",
|
</span>
|
||||||
{ "text-primary": isActive },
|
)}
|
||||||
)}
|
<span>{label}</span>
|
||||||
>
|
{children}
|
||||||
{icon}
|
</Link>
|
||||||
</span>
|
</div>
|
||||||
)}
|
)
|
||||||
<span>{label}</span>
|
}
|
||||||
{children}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
SidebarItem.displayName = "SidebarItem"
|
SidebarItem.displayName = "SidebarItem"
|
||||||
|
|
||||||
const LogoAndSearch: React.FC = React.memo(() => {
|
const LogoAndSearch: React.FC = () => {
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -105,11 +109,11 @@ const LogoAndSearch: React.FC = React.memo(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
|
||||||
LogoAndSearch.displayName = "LogoAndSearch"
|
LogoAndSearch.displayName = "LogoAndSearch"
|
||||||
|
|
||||||
const SidebarContent: React.FC = React.memo(() => {
|
const SidebarContent: React.FC = () => {
|
||||||
const { me } = useAccountOrGuest()
|
const { me } = useAccountOrGuest()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -119,15 +123,15 @@ const SidebarContent: React.FC = React.memo(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="relative mt-1.5 flex grow flex-col overflow-y-auto rounded-md px-3 outline-none">
|
<div className="relative mt-1.5 flex grow flex-col overflow-y-auto rounded-md px-3 outline-none">
|
||||||
<div className="h-2 shrink-0" />
|
<div className="h-2 shrink-0" />
|
||||||
{me._type === "Account" && <LinkCollection />}
|
{me?._type === "Account" && <LinkCollection />}
|
||||||
{me._type === "Account" && <JournalSection />}
|
{me?._type === "Account" && <JournalSection />}
|
||||||
{me._type === "Account" && <PageSection />}
|
{me?._type === "Account" && <PageSection />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ProfileSection />
|
<ProfileSection />
|
||||||
</nav>
|
</nav>
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
|
||||||
SidebarContent.displayName = "SidebarContent"
|
SidebarContent.displayName = "SidebarContent"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user