@tayacrystals/lore 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,7 +21,7 @@ const docsHref = `${BASE_URL}docs`;
21
21
  return <SidebarItem label={entry.label} href={entry.href} active={entry.href === currentPath} icon={entry.icon} />;
22
22
  }
23
23
  return (
24
- <SidebarGroup label={entry.label} items={entry.items} currentPath={currentPath} depth={0} />
24
+ <SidebarGroup label={entry.label} items={entry.items} currentPath={currentPath} depth={0} href={entry.href} />
25
25
  );
26
26
  })
27
27
  }
@@ -8,30 +8,41 @@ interface Props {
8
8
  items: SidebarEntry[];
9
9
  currentPath: string;
10
10
  depth?: number;
11
+ href?: string;
11
12
  }
12
13
 
13
- const { label, items, currentPath, depth = 0 } = Astro.props;
14
+ const { label, items, currentPath, depth = 0, href } = Astro.props;
14
15
 
15
16
  function hasActiveDescendant(entries: SidebarEntry[], path: string): boolean {
16
17
  for (const entry of entries) {
17
18
  if (entry.type === "link" && entry.href === path) return true;
18
- if (entry.type === "group" && hasActiveDescendant(entry.items, path)) return true;
19
+ if (entry.type === "group") {
20
+ if (entry.href === path) return true;
21
+ if (hasActiveDescendant(entry.items, path)) return true;
22
+ }
19
23
  }
20
24
  return false;
21
25
  }
22
26
 
23
- const isOpen = hasActiveDescendant(items, currentPath);
27
+ const isSelfActive = href ? href === currentPath : false;
28
+ const isOpen = isSelfActive || hasActiveDescendant(items, currentPath);
24
29
  ---
25
30
 
26
31
  {depth === 0 ? (
27
32
  <div class="mt-4 first:mt-0">
28
- <p class="px-2 mb-1 text-xs font-semibold text-fd-foreground/80 tracking-wide">{label}</p>
33
+ {href ? (
34
+ <a href={href} class:list={["block px-2 mb-1 text-xs font-semibold tracking-wide no-underline", isSelfActive ? "text-fd-primary" : "text-fd-foreground/80 hover:text-fd-foreground"]}>
35
+ {label}
36
+ </a>
37
+ ) : (
38
+ <p class="px-2 mb-1 text-xs font-semibold text-fd-foreground/80 tracking-wide">{label}</p>
39
+ )}
29
40
  <div class="space-y-0.5">
30
41
  {items.map((item) =>
31
42
  item.type === "link" ? (
32
43
  <SidebarItem label={item.label} href={item.href} active={item.href === currentPath} icon={item.icon} />
33
44
  ) : (
34
- <Astro.self label={item.label} items={item.items} currentPath={currentPath} depth={depth + 1} />
45
+ <Astro.self label={item.label} items={item.items} currentPath={currentPath} depth={depth + 1} href={item.href} />
35
46
  )
36
47
  )}
37
48
  </div>
@@ -40,14 +51,20 @@ const isOpen = hasActiveDescendant(items, currentPath);
40
51
  <details class="group/sub" open={isOpen}>
41
52
  <summary class="flex items-center gap-1 px-2 py-1.5 text-[13px] font-medium text-fd-muted-foreground hover:text-fd-foreground cursor-pointer select-none list-none [&::-webkit-details-marker]:hidden">
42
53
  <Icon name="lucide:chevron-right" class="w-3 h-3 shrink-0 transition-transform group-open/sub:rotate-90" />
43
- {label}
54
+ {href ? (
55
+ <a href={href} class:list={["no-underline", isSelfActive ? "text-fd-primary" : "text-fd-muted-foreground hover:text-fd-foreground"]}>
56
+ {label}
57
+ </a>
58
+ ) : (
59
+ label
60
+ )}
44
61
  </summary>
45
62
  <div class="ml-3 pl-2 border-l border-fd-border/50 space-y-0.5 mt-0.5">
46
63
  {items.map((item) =>
47
64
  item.type === "link" ? (
48
65
  <SidebarItem label={item.label} href={item.href} active={item.href === currentPath} icon={item.icon} />
49
66
  ) : (
50
- <Astro.self label={item.label} items={item.items} currentPath={currentPath} depth={depth + 1} />
67
+ <Astro.self label={item.label} items={item.items} currentPath={currentPath} depth={depth + 1} href={item.href} />
51
68
  )
52
69
  )}
53
70
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tayacrystals/lore",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.ts",
package/routes/docs.astro CHANGED
@@ -24,9 +24,14 @@ export async function getStaticPaths() {
24
24
  const entries: DocsEntry[] = await getCollection("docs", ({ data }: DocsEntry) => !data.draft);
25
25
 
26
26
  // Content entry paths
27
+ // Map subfolder index files (e.g. "getting-started/index") to their parent path
27
28
  const entryPaths = entries.map((entry: DocsEntry) => ({
28
29
  params: {
29
- slug: entry.id === "index" ? undefined : entry.id,
30
+ slug: entry.id === "index"
31
+ ? undefined
32
+ : entry.id.endsWith("/index")
33
+ ? entry.id.slice(0, -"/index".length)
34
+ : entry.id,
30
35
  },
31
36
  props: { entry, isSection: false as const },
32
37
  }));
@@ -43,8 +48,13 @@ export async function getStaticPaths() {
43
48
 
44
49
  // Only create section pages for groups that don't have a matching content entry
45
50
  const entryIds = new Set(entries.map((e: DocsEntry) => e.id));
51
+ const indexSlugs = new Set(
52
+ entries
53
+ .filter((e: DocsEntry) => e.id.endsWith("/index"))
54
+ .map((e: DocsEntry) => e.id.slice(0, -"/index".length)),
55
+ );
46
56
  const sectionPaths = [...groupSlugs]
47
- .filter((slug) => !entryIds.has(slug))
57
+ .filter((slug) => !entryIds.has(slug) && !indexSlugs.has(slug))
48
58
  .map((slug) => ({
49
59
  params: { slug },
50
60
  props: { groupSlug: slug, isSection: true as const },
@@ -11,6 +11,9 @@ export function flattenSidebar(entries: SidebarEntry[]): FlatNavItem[] {
11
11
  if (entry.type === "link") {
12
12
  result.push({ label: entry.label, href: entry.href });
13
13
  } else {
14
+ if (entry.href) {
15
+ result.push({ label: entry.label, href: entry.href });
16
+ }
14
17
  result.push(...flattenSidebar(entry.items));
15
18
  }
16
19
  }
package/utils/sidebar.ts CHANGED
@@ -16,6 +16,7 @@ export interface SidebarGroup {
16
16
  label: string;
17
17
  order: number;
18
18
  slug: string;
19
+ href?: string;
19
20
  items: SidebarEntry[];
20
21
  }
21
22
 
@@ -54,6 +55,8 @@ function buildLevel(
54
55
  groups.set(groupSlug, []);
55
56
  }
56
57
  groups.get(groupSlug)!.push(entry);
58
+ } else if (relativePath === "index" && depth > 0) {
59
+ // Skip index files in subfolders — they're used as the group's own page
57
60
  } else {
58
61
  const href = entry.id === "index" ? `${BASE_URL}docs` : `${BASE_URL}docs/${entry.id}`;
59
62
  topLevel.push({
@@ -80,14 +83,21 @@ function buildLevel(
80
83
  const config = configAtLevel[slug];
81
84
  const childConfig = config?.children ?? {};
82
85
 
86
+ // Check for an index entry in this group
87
+ const indexEntry = groupEntries.find((e) => {
88
+ const rel = e.id.slice(fullSlug.length + 1);
89
+ return rel === "index";
90
+ });
91
+
83
92
  const items = buildLevel(groupEntries, childConfig, fullSlug, depth + 1);
84
93
  items.sort((a, b) => a.order - b.order);
85
94
 
86
95
  result.push({
87
96
  type: "group",
88
97
  label: config?.label ?? titleCase(slug),
89
- order: config?.order ?? 999,
98
+ order: config?.order ?? (indexEntry ? indexEntry.data.order : 999),
90
99
  slug: fullSlug,
100
+ href: indexEntry ? `${BASE_URL}docs/${fullSlug}` : undefined,
91
101
  items,
92
102
  });
93
103
  }