jamdesk 1.1.143 → 1.1.144

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jamdesk",
3
- "version": "1.1.143",
3
+ "version": "1.1.144",
4
4
  "description": "CLI for Jamdesk — build, preview, and deploy documentation sites from MDX. Dev server with hot reload, 50+ components, OpenAPI support, AI search, and Mintlify migration",
5
5
  "keywords": [
6
6
  "jamdesk",
@@ -6,7 +6,7 @@ import Link from 'next/link';
6
6
  import { usePathname } from 'next/navigation';
7
7
  // Icons use Font Awesome CSS classes for lightweight rendering
8
8
  import type { DocsConfig, TabsPosition } from '@/lib/docs-types';
9
- import { normalizeLogo, getIconName } from '@/lib/docs-types';
9
+ import { normalizeLogo, getIconString } from '@/lib/docs-types';
10
10
  import type { LayoutVariant } from '@/themes';
11
11
  import { getTheme } from '@/themes';
12
12
  import { ThemeToggle } from '@/components/theme/ThemeToggle';
@@ -136,7 +136,7 @@ export function Header({ config, layout = 'header-logo', tabsPosition: tabsPosit
136
136
  if (!hasTabs) return [];
137
137
 
138
138
  return navigationTabs.map((tab) => {
139
- const iconName = getIconName(tab.icon);
139
+ const iconName = getIconString(tab.icon);
140
140
 
141
141
  // For external tabs, use the href directly
142
142
  if (tab.href && !tab.groups && !tab.pages) {
@@ -489,7 +489,7 @@ export function Header({ config, layout = 'header-logo', tabsPosition: tabsPosit
489
489
  rel={isExternal ? 'noopener noreferrer' : undefined}
490
490
  className="flex items-center gap-1.5 px-2.5 py-1.5 text-sm text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] transition-colors"
491
491
  >
492
- {link.icon && <i className={`${getIconClass(getIconName(link.icon))} text-[14px]`} aria-hidden="true" />}
492
+ {link.icon && <i className={`${getIconClass(getIconString(link.icon))} text-[14px]`} aria-hidden="true" />}
493
493
  <span>{resolveLabel(link.label, link.labels)}</span>
494
494
  {isExternal && <i className="fa-solid fa-arrow-up-right-from-square text-[10px] opacity-50" aria-hidden="true" />}
495
495
  </a>
@@ -564,6 +564,7 @@ export function Header({ config, layout = 'header-logo', tabsPosition: tabsPosit
564
564
  isOpen={isSearchOpen}
565
565
  onClose={() => setIsSearchOpen(false)}
566
566
  popularPages={config.search?.popularPages}
567
+ placeholder={config.search?.prompt}
567
568
  />
568
569
  )}
569
570
  {searchDevNotice}
@@ -12,11 +12,13 @@ import { useProjectSlug } from '@/lib/project-slug-context';
12
12
  import type { SearchResult, SearchGroup } from '@/lib/search-client';
13
13
  import { useChatPanelOptional } from '@/hooks/useChatPanel';
14
14
  import { modifierKeyLabel } from '@/lib/platform-keys';
15
+ import { getIconString, type IconConfig } from '@/lib/docs-types';
16
+ import { getIconClass } from '@/lib/icon-utils';
15
17
 
16
18
  interface PopularPage {
17
19
  title: string;
18
20
  slug: string;
19
- icon?: string;
21
+ icon?: IconConfig;
20
22
  }
21
23
 
22
24
  interface SearchModalProps {
@@ -24,10 +26,14 @@ interface SearchModalProps {
24
26
  onClose: () => void;
25
27
  popularPages?: PopularPage[];
26
28
  onNavigate?: (url: string) => void;
29
+ /** Custom placeholder for the search input (docs.json `search.prompt`) */
30
+ placeholder?: string;
27
31
  }
28
32
 
29
33
  const DEBOUNCE_MS = 150;
30
34
 
35
+ const DEFAULT_SEARCH_PLACEHOLDER = 'Search documentation…';
36
+
31
37
  // Default popular pages fallback
32
38
  const DEFAULT_POPULAR_PAGES: PopularPage[] = [
33
39
  { title: 'Quick Start', slug: 'quickstart', icon: 'rocket' },
@@ -135,7 +141,7 @@ function countVisibleResults(rows: SearchRow[]): number {
135
141
  return rows.reduce((n, r) => (r.kind === 'expander' ? n : n + 1), 0);
136
142
  }
137
143
 
138
- export function SearchModal({ isOpen, onClose, popularPages, onNavigate }: SearchModalProps) {
144
+ export function SearchModal({ isOpen, onClose, popularPages, onNavigate, placeholder }: SearchModalProps) {
139
145
  const linkPrefix = useLinkPrefix();
140
146
  const projectSlug = useProjectSlug();
141
147
  const chatPanel = useChatPanelOptional();
@@ -522,7 +528,7 @@ export function SearchModal({ isOpen, onClose, popularPages, onNavigate }: Searc
522
528
  <input
523
529
  ref={inputRef}
524
530
  type="search"
525
- placeholder="Search documentation…"
531
+ placeholder={placeholder || DEFAULT_SEARCH_PLACEHOLDER}
526
532
  value={query}
527
533
  onChange={(e) => setQuery(e.target.value)}
528
534
  className="flex-1 bg-transparent text-[var(--color-text-primary)] placeholder-[var(--color-text-muted)] outline-none text-base [&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none"
@@ -703,7 +709,7 @@ export function SearchModal({ isOpen, onClose, popularPages, onNavigate }: Searc
703
709
  : 'hover:bg-[var(--color-bg-secondary)]'
704
710
  }`}
705
711
  >
706
- <i className={`fa-light fa-${page.icon || 'file-lines'} text-sm text-[var(--color-text-muted)]`} aria-hidden="true" />
712
+ <i className={`${getIconClass(getIconString(page.icon))} text-sm text-[var(--color-text-muted)]`} aria-hidden="true" />
707
713
  <span className="text-sm text-[var(--color-text-primary)] truncate">{page.title}</span>
708
714
  </button>
709
715
  ))}
@@ -685,7 +685,7 @@ export interface SearchConfig {
685
685
  popularPages?: Array<{
686
686
  title: string;
687
687
  slug: string;
688
- icon?: string;
688
+ icon?: IconConfig;
689
689
  }>;
690
690
  }
691
691
 
@@ -960,7 +960,7 @@ export function normalizeNavPage(page: NavigationPage): {
960
960
  .pop()
961
961
  ?.replace(/-/g, ' ')
962
962
  .replace(/\b\w/g, (l) => l.toUpperCase()) || page.page,
963
- icon: getIconName(page.icon),
963
+ icon: getIconString(page.icon),
964
964
  tag: page.tag,
965
965
  };
966
966
  }
@@ -1024,6 +1024,19 @@ export function getIconName(icon: IconConfig | undefined): string | undefined {
1024
1024
  return icon.name;
1025
1025
  }
1026
1026
 
1027
+ /**
1028
+ * Flatten an icon config to the string getIconClass() understands, preserving
1029
+ * the Font Awesome style as a "style/name" prefix (every IconStyle value is a
1030
+ * getIconClass style prefix). Use this — not getIconName — wherever an icon is
1031
+ * rendered, so a configured `style` survives the flatten. `library` is
1032
+ * intentionally dropped: all icons render via Font Awesome.
1033
+ */
1034
+ export function getIconString(icon: IconConfig | undefined): string | undefined {
1035
+ if (!icon) return undefined;
1036
+ if (typeof icon === 'string') return icon;
1037
+ return icon.style ? `${icon.style}/${icon.name}` : icon.name;
1038
+ }
1039
+
1027
1040
  /**
1028
1041
  * Get icon library from config
1029
1042
  */
@@ -18,7 +18,7 @@ import type {
18
18
  ExternalAnchorConfig,
19
19
  } from './docs-types';
20
20
 
21
- import { normalizeNavPage, getIconName } from './docs-types';
21
+ import { normalizeNavPage, getIconString } from './docs-types';
22
22
  import { getLanguageDisplayInfo, extractLanguageFromPath } from './language-utils';
23
23
  import { evictOldest } from './cache-utils';
24
24
 
@@ -225,7 +225,7 @@ function resolveGroup(group: GroupConfig): ResolvedGroup {
225
225
 
226
226
  return {
227
227
  name: group.group,
228
- icon: getIconName(group.icon),
228
+ icon: getIconString(group.icon),
229
229
  tag: group.tag,
230
230
  pages: resolvedPages,
231
231
  expanded: group.expanded,
@@ -268,7 +268,7 @@ function resolveTabGroups(tab: TabConfig): ResolvedGroup[] {
268
268
  function resolveTab(tab: TabConfig): ResolvedTab {
269
269
  return {
270
270
  name: tab.tab,
271
- icon: getIconName(tab.icon),
271
+ icon: getIconString(tab.icon),
272
272
  href: tab.href,
273
273
  isExternal: !!tab.href && !tab.groups && !tab.pages,
274
274
  };
@@ -465,7 +465,7 @@ export function resolveNavigation(
465
465
  .map((anchor: ExternalAnchorConfig) => ({
466
466
  name: anchor.name,
467
467
  href: anchor.href,
468
- icon: getIconName(anchor.icon),
468
+ icon: getIconString(anchor.icon),
469
469
  }));
470
470
  }
471
471
 
@@ -476,7 +476,7 @@ export function resolveNavigation(
476
476
  result.externalAnchors.push({
477
477
  name: anchor.anchor,
478
478
  href: anchor.href,
479
- icon: getIconName(anchor.icon),
479
+ icon: getIconString(anchor.icon),
480
480
  });
481
481
  }
482
482
  }
@@ -555,7 +555,7 @@
555
555
  "slug": {
556
556
  "type": "string",
557
557
  "minLength": 1,
558
- "description": "Page path (without .mdx extension)"
558
+ "description": "Page path, without a leading slash or file extension. A leading slash makes a broken // URL. Nested pages use the folder path: e.g. 'quickstart', or 'guides/authentication' for the file guides/authentication.mdx."
559
559
  },
560
560
  "icon": {
561
561
  "$ref": "#/definitions/iconSchema",