mirror of
https://github.com/linsa-io/linsa.git
synced 2026-04-24 17:28:41 +02:00
* start * . * seeding connections * . * wip * wip: learning state * wip: notes section * wip: many * topics * chore: update schema * update package * update sidebar * update page section * feat: profile * fix: remove z index * fix: wrong type * add avatar * add avatar * wip * . * store page section key * remove atom page section * fix rerender * fix rerender * fix rerender * fix rerender * fix link * search light/dark mode * bubble menu ui * . * fix: remove unecessary code * chore: mark as old for old schema * chore: adapt new schema * fix: add topic schema but null for now * fix: add icon on personal link * fix: list item * fix: set url fetched when editing * fix: remove image * feat: add icon to link * feat: custom url zod validation * fix: metadata test * chore: update utils * fix: link * fix: url fetcher * . * . * fix: add link, section * chore: seeder * . * . * . * . * fix: change checkbox to learning state * fix: click outside editing form * feat: constant * chore: move to master folder * chore: adapt new schema * chore: cli for new schema * fix: new schema for dev seed * fix: seeding * update package * chore: forcegraph seed * bottombar * if isEdit delete icon * showCreate X button * . * options * chore: implement topic from public global group * chore: update learning state * fix: change implementation for outside click * chore: implement new form param * chore: update env example * feat: link form refs exception * new page button layout, link topic search fixed * chore: enable topic * chore: update seed * profile * chore: move framer motion package from root to web and add nuqs * chore: add LearningStateValue * chore: implement active state * profile * chore: use fancy switch and update const * feat: filter implementation * dropdown menu * . * sidebar topics * topic selected color * feat: topic detail * fix: collapsible page * pages - sorted by, layout, visible mode * . * . * . * topic status sidebar * topic button and count * fix: topic * page delete/topic buttons * search ui * selected topic for page * selected topic status sidebar * removed footer * update package * . --------- Co-authored-by: Nikita <github@nikiv.dev> Co-authored-by: marshennikovaolga <marshennikova@gmail.com> Co-authored-by: Kisuyo <ig.intr3st@gmail.com>
109 lines
3.1 KiB
TypeScript
109 lines
3.1 KiB
TypeScript
"use client"
|
|
|
|
import React from "react"
|
|
import Link from "next/link"
|
|
import { useCoState } from "@/lib/providers/jazz-provider"
|
|
import { PublicGlobalGroup } from "@/lib/schema/master/public-group"
|
|
import { ID } from "jazz-tools"
|
|
import { TopicDetailHeader } from "./Header"
|
|
import { LaIcon } from "@/components/custom/la-icon"
|
|
import { cn, ensureUrlProtocol } from "@/lib/utils"
|
|
import { Section as SectionSchema, Link as LinkSchema } from "@/lib/schema"
|
|
|
|
interface TopicDetailRouteProps {
|
|
topicName: string
|
|
}
|
|
|
|
export function TopicDetailRoute({ topicName }: TopicDetailRouteProps) {
|
|
const topics = useCoState(PublicGlobalGroup, process.env.NEXT_PUBLIC_JAZZ_GLOBAL_GROUP as ID<PublicGlobalGroup>, {
|
|
root: {
|
|
topics: []
|
|
}
|
|
})
|
|
|
|
const topic = topics?.root.topics.find(topic => topic?.name === topicName)
|
|
|
|
if (!topic) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-full flex-auto flex-col">
|
|
<TopicDetailHeader topic={topic} />
|
|
<div className="flex w-full flex-1 flex-col gap-4 focus-visible:outline-none">
|
|
<div tabIndex={-1} className="outline-none">
|
|
<div className="flex flex-1 flex-col gap-4" role="listbox" aria-label="Topic sections">
|
|
{topic.latestGlobalGuide?.sections?.map(
|
|
(section, index) => section?.id && <Section key={index} section={section} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface SectionProps {
|
|
section: SectionSchema
|
|
}
|
|
|
|
function Section({ section }: SectionProps) {
|
|
return (
|
|
<div className="flex flex-col">
|
|
<div className="flex items-center gap-4 px-4 py-2">
|
|
<p className="text-foreground text-sm font-medium">{section.title}</p>
|
|
<div className="border-b-secondary flex-1 border-b"></div>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-px py-2">
|
|
{section.links?.map((link, index) => link?.url && <LinkItem key={index} link={link} />)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface LinkItemProps {
|
|
link: LinkSchema
|
|
}
|
|
|
|
function LinkItem({ link }: LinkItemProps) {
|
|
return (
|
|
<li
|
|
tabIndex={0}
|
|
className={cn("hover:bg-muted/50 relative flex h-14 cursor-default items-center outline-none xl:h-11")}
|
|
>
|
|
<div className="flex grow justify-between gap-x-6 px-6 max-lg:px-4">
|
|
<div className="flex min-w-0 items-center gap-x-4">
|
|
<LaIcon name="GraduationCap" className="size-5" />
|
|
<div className="w-full min-w-0 flex-auto">
|
|
<div className="gap-x-2 space-y-0.5 xl:flex xl:flex-row">
|
|
<p className="text-primary hover:text-primary line-clamp-1 text-sm font-medium xl:truncate">
|
|
{link.title}
|
|
</p>
|
|
|
|
<div className="group flex items-center gap-x-1">
|
|
<LaIcon
|
|
name="Link"
|
|
aria-hidden="true"
|
|
className="text-muted-foreground group-hover:text-primary size-3 flex-none"
|
|
/>
|
|
<Link
|
|
href={ensureUrlProtocol(link.url)}
|
|
passHref
|
|
prefetch={false}
|
|
target="_blank"
|
|
onClick={e => e.stopPropagation()}
|
|
className="text-muted-foreground hover:text-primary text-xs"
|
|
>
|
|
<span className="xl:truncate">{link.url}</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex shrink-0 items-center gap-x-4"></div>
|
|
</div>
|
|
</li>
|
|
)
|
|
}
|