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"
|
||||
|
||||
export const JournalSection: React.FC = () => {
|
||||
const { me } = useAccount()
|
||||
const journalEntries = me?.root?.journalEntries
|
||||
const { me } = useAccount({ root: { journalEntries: [{}] } })
|
||||
const journalEntries = me?.root.journalEntries
|
||||
|
||||
const [, setIsFetching] = 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"
|
||||
|
||||
export const LinkCollection: React.FC = () => {
|
||||
const { me } = useAccount({
|
||||
root: {
|
||||
personalLinks: [],
|
||||
personalPages: [],
|
||||
topicsWantToLearn: [],
|
||||
topicsLearning: [],
|
||||
topicsLearned: [],
|
||||
tasks: [],
|
||||
},
|
||||
})
|
||||
const { me } = useAccount()
|
||||
|
||||
const linkCount = me?.root.personalLinks?.length || 0
|
||||
const pageCount = me?.root.personalPages?.length || 0
|
||||
const taskCount = me?.root.tasks?.length || 0
|
||||
const linkCount = me?.root?.personalLinks?.length || 0
|
||||
const pageCount = me?.root?.personalPages?.length || 0
|
||||
const taskCount = me?.root?.tasks?.length || 0
|
||||
|
||||
const topicCount =
|
||||
(me?.root.topicsWantToLearn?.length || 0) +
|
||||
(me?.root.topicsLearning?.length || 0) +
|
||||
(me?.root.topicsLearned?.length || 0)
|
||||
(me?.root?.topicsWantToLearn?.length || 0) +
|
||||
(me?.root?.topicsLearning?.length || 0) +
|
||||
(me?.root?.topicsLearned?.length || 0)
|
||||
|
||||
return (
|
||||
<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 { useAtom } from "jotai"
|
||||
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 { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
@@ -49,9 +49,14 @@ const isExpandedAtom = atomWithStorage("isPageSectionExpanded", true)
|
||||
export const PageSection: React.FC = () => {
|
||||
const { me } = useAccount({
|
||||
root: {
|
||||
personalPages: [{}],
|
||||
personalPages: [
|
||||
{
|
||||
topic: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const [sort] = useAtom(pageSortAtom)
|
||||
const [show] = useAtom(pageShowAtom)
|
||||
const [isExpanded, setIsExpanded] = useAtom(isExpandedAtom)
|
||||
@@ -163,23 +168,13 @@ const PageSectionHeader: React.FC<PageSectionHeaderProps> = ({
|
||||
)
|
||||
|
||||
const NewPageButton: React.FC = () => {
|
||||
const { me } = useAccount()
|
||||
const navigate = useNavigate()
|
||||
const { newPage } = usePageActions()
|
||||
|
||||
const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
const page = newPage(me)
|
||||
|
||||
if (page.id) {
|
||||
navigate({
|
||||
to: "/pages/$pageId",
|
||||
params: { pageId: page.id },
|
||||
replace: true,
|
||||
})
|
||||
}
|
||||
newPage()
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -38,44 +38,48 @@ const useSidebarCollapse = (
|
||||
return [isCollapsed, setIsCollapsed]
|
||||
}
|
||||
|
||||
const SidebarItem: React.FC<SidebarItemProps> = React.memo(
|
||||
({ label, url, icon, onClick, children }) => {
|
||||
const { pathname } = useLocation()
|
||||
const isActive = pathname === url
|
||||
const SidebarItem: React.FC<SidebarItemProps> = ({
|
||||
label,
|
||||
url,
|
||||
icon,
|
||||
onClick,
|
||||
children,
|
||||
}) => {
|
||||
const { pathname } = useLocation()
|
||||
const isActive = pathname === url
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"group relative my-0.5 rounded-md",
|
||||
isActive ? "bg-secondary/80" : "hover:bg-secondary/40",
|
||||
)}
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"group relative my-0.5 rounded-md",
|
||||
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
|
||||
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}
|
||||
>
|
||||
{icon && (
|
||||
<span
|
||||
className={cn(
|
||||
"mr-2 size-4 text-primary/60 group-hover:text-primary",
|
||||
{ "text-primary": isActive },
|
||||
)}
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
)}
|
||||
<span>{label}</span>
|
||||
{children}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
)
|
||||
{icon && (
|
||||
<span
|
||||
className={cn(
|
||||
"mr-2 size-4 text-primary/60 group-hover:text-primary",
|
||||
{ "text-primary": isActive },
|
||||
)}
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
)}
|
||||
<span>{label}</span>
|
||||
{children}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
SidebarItem.displayName = "SidebarItem"
|
||||
|
||||
const LogoAndSearch: React.FC = React.memo(() => {
|
||||
const LogoAndSearch: React.FC = () => {
|
||||
const { pathname } = useLocation()
|
||||
|
||||
return (
|
||||
@@ -105,11 +109,11 @@ const LogoAndSearch: React.FC = React.memo(() => {
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
LogoAndSearch.displayName = "LogoAndSearch"
|
||||
|
||||
const SidebarContent: React.FC = React.memo(() => {
|
||||
const SidebarContent: React.FC = () => {
|
||||
const { me } = useAccountOrGuest()
|
||||
|
||||
return (
|
||||
@@ -119,15 +123,15 @@ const SidebarContent: React.FC = React.memo(() => {
|
||||
</div>
|
||||
<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" />
|
||||
{me._type === "Account" && <LinkCollection />}
|
||||
{me._type === "Account" && <JournalSection />}
|
||||
{me._type === "Account" && <PageSection />}
|
||||
{me?._type === "Account" && <LinkCollection />}
|
||||
{me?._type === "Account" && <JournalSection />}
|
||||
{me?._type === "Account" && <PageSection />}
|
||||
</div>
|
||||
|
||||
<ProfileSection />
|
||||
</nav>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
SidebarContent.displayName = "SidebarContent"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user