@netfoundry/docusaurus-theme 0.8.2 → 0.10.0

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.
Files changed (86) hide show
  1. package/css/layout.css +37 -0
  2. package/css/product-picker.css +36 -8
  3. package/css/theme.css +51 -20
  4. package/css/vars.css +1 -0
  5. package/dist/css/layout.css +37 -0
  6. package/dist/css/product-picker.css +36 -8
  7. package/dist/css/theme.css +51 -20
  8. package/dist/css/vars.css +1 -0
  9. package/dist/src/components/AssetsContext/AssetsContext.d.ts +14 -0
  10. package/dist/src/components/AssetsContext/AssetsContext.d.ts.map +1 -0
  11. package/dist/src/components/AssetsContext/AssetsContext.js +31 -0
  12. package/dist/src/components/AssetsContext/AssetsContext.js.map +1 -0
  13. package/dist/src/components/AssetsContext/index.d.ts +3 -0
  14. package/dist/src/components/AssetsContext/index.d.ts.map +1 -0
  15. package/dist/src/components/AssetsContext/index.js +2 -0
  16. package/dist/src/components/AssetsContext/index.js.map +1 -0
  17. package/dist/src/components/DownloadCard/DownloadCard.d.ts +20 -0
  18. package/dist/src/components/DownloadCard/DownloadCard.d.ts.map +1 -0
  19. package/dist/src/components/DownloadCard/DownloadCard.js +87 -0
  20. package/dist/src/components/DownloadCard/DownloadCard.js.map +1 -0
  21. package/dist/src/components/DownloadCard/DownloadCard.module.css +122 -0
  22. package/dist/src/components/DownloadCard/index.d.ts +3 -0
  23. package/dist/src/components/DownloadCard/index.d.ts.map +1 -0
  24. package/dist/src/components/DownloadCard/index.js +2 -0
  25. package/dist/src/components/DownloadCard/index.js.map +1 -0
  26. package/dist/src/components/DownloadCard/logos.d.ts +5 -0
  27. package/dist/src/components/DownloadCard/logos.d.ts.map +1 -0
  28. package/dist/src/components/DownloadCard/logos.js +10 -0
  29. package/dist/src/components/DownloadCard/logos.js.map +1 -0
  30. package/dist/src/components/NetFoundryFooter/NetFoundryFooter.d.ts.map +1 -1
  31. package/dist/src/components/NetFoundryFooter/NetFoundryFooter.js +3 -2
  32. package/dist/src/components/NetFoundryFooter/NetFoundryFooter.js.map +1 -1
  33. package/dist/src/components/NetFoundryFooter/styles.module.css +1 -1
  34. package/dist/src/components/icons/DiscourseIcon.d.ts +8 -0
  35. package/dist/src/components/icons/DiscourseIcon.d.ts.map +1 -0
  36. package/dist/src/components/icons/DiscourseIcon.js +5 -0
  37. package/dist/src/components/icons/DiscourseIcon.js.map +1 -0
  38. package/dist/src/components/icons/GitHubIcon.d.ts +8 -0
  39. package/dist/src/components/icons/GitHubIcon.d.ts.map +1 -0
  40. package/dist/src/components/icons/GitHubIcon.js +5 -0
  41. package/dist/src/components/icons/GitHubIcon.js.map +1 -0
  42. package/dist/src/components/icons/XIcon.d.ts +8 -0
  43. package/dist/src/components/icons/XIcon.d.ts.map +1 -0
  44. package/dist/src/components/icons/XIcon.js +5 -0
  45. package/dist/src/components/icons/XIcon.js.map +1 -0
  46. package/dist/src/components/icons/YouTubeIcon.d.ts +8 -0
  47. package/dist/src/components/icons/YouTubeIcon.d.ts.map +1 -0
  48. package/dist/src/components/icons/YouTubeIcon.js +5 -0
  49. package/dist/src/components/icons/YouTubeIcon.js.map +1 -0
  50. package/dist/src/components/icons/index.d.ts +5 -0
  51. package/dist/src/components/icons/index.d.ts.map +1 -0
  52. package/dist/src/components/icons/index.js +5 -0
  53. package/dist/src/components/icons/index.js.map +1 -0
  54. package/dist/src/components/index.d.ts +2 -0
  55. package/dist/src/components/index.d.ts.map +1 -1
  56. package/dist/src/components/index.js +2 -0
  57. package/dist/src/components/index.js.map +1 -1
  58. package/dist/src/index.d.ts.map +1 -1
  59. package/dist/src/index.js +5 -0
  60. package/dist/src/index.js.map +1 -1
  61. package/dist/theme/NavbarItem/ComponentTypes.d.ts +4 -0
  62. package/dist/theme/NavbarItem/ComponentTypes.d.ts.map +1 -1
  63. package/dist/theme/NavbarItem/ComponentTypes.js +4 -0
  64. package/dist/theme/NavbarItem/ComponentTypes.js.map +1 -1
  65. package/dist/theme/NavbarItem/NavbarPicker.d.ts +13 -0
  66. package/dist/theme/NavbarItem/NavbarPicker.d.ts.map +1 -0
  67. package/dist/theme/NavbarItem/NavbarPicker.js +59 -0
  68. package/dist/theme/NavbarItem/NavbarPicker.js.map +1 -0
  69. package/dist/theme/NavbarItem/types/IconLinks/index.d.ts +4 -0
  70. package/dist/theme/NavbarItem/types/IconLinks/index.d.ts.map +1 -0
  71. package/dist/theme/NavbarItem/types/IconLinks/index.js +22 -0
  72. package/dist/theme/NavbarItem/types/IconLinks/index.js.map +1 -0
  73. package/dist/theme/NavbarItem/types/ProductPicker/index.d.ts.map +1 -1
  74. package/dist/theme/NavbarItem/types/ProductPicker/index.js +3 -49
  75. package/dist/theme/NavbarItem/types/ProductPicker/index.js.map +1 -1
  76. package/dist/theme/NavbarItem/types/ResourcesPicker/index.d.ts +8 -0
  77. package/dist/theme/NavbarItem/types/ResourcesPicker/index.d.ts.map +1 -0
  78. package/dist/theme/NavbarItem/types/ResourcesPicker/index.js +30 -0
  79. package/dist/theme/NavbarItem/types/ResourcesPicker/index.js.map +1 -0
  80. package/package.json +2 -2
  81. package/theme/NavbarItem/ComponentTypes.tsx +4 -0
  82. package/theme/NavbarItem/NavbarPicker.tsx +94 -0
  83. package/theme/NavbarItem/types/IconLinks/index.tsx +35 -0
  84. package/theme/NavbarItem/types/ProductPicker/index.tsx +88 -154
  85. package/theme/NavbarItem/types/ResourcesPicker/index.tsx +88 -0
  86. package/css/.claude/settings.local.json +0 -12
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ import { DiscourseIcon, GitHubIcon } from '../../../../src/components/icons';
4
+ const GITHUB_ROUTES = {
5
+ '/docs/openziti': 'https://github.com/openziti/ziti',
6
+ '/docs/zrok': 'https://github.com/openziti/zrok',
7
+ };
8
+ export default function IconLinks(_props) {
9
+ const [githubUrl, setGithubUrl] = useState(null);
10
+ useEffect(() => {
11
+ const check = () => {
12
+ const { pathname } = window.location;
13
+ const entry = Object.entries(GITHUB_ROUTES).find(([p]) => pathname.startsWith(p));
14
+ setGithubUrl(entry ? entry[1] : null);
15
+ };
16
+ check();
17
+ window.addEventListener('popstate', check);
18
+ return () => window.removeEventListener('popstate', check);
19
+ }, []);
20
+ return (_jsxs("div", { className: "nf-icon-links", children: [githubUrl && (_jsx("a", { href: githubUrl, target: "_blank", rel: "noopener noreferrer", className: "nf-icon-link", title: "GitHub", children: _jsx(GitHubIcon, {}) })), _jsx("a", { href: "https://openziti.discourse.group/", target: "_blank", rel: "noopener noreferrer", className: "nf-icon-link nf-icon-link--discourse", title: "Discourse", children: _jsx(DiscourseIcon, {}) })] }));
21
+ }
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../theme/NavbarItem/types/IconLinks/index.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAC,QAAQ,EAAE,SAAS,EAAC,MAAM,OAAO,CAAC;AACjD,OAAO,EAAC,aAAa,EAAE,UAAU,EAAC,MAAM,kCAAkC,CAAC;AAE3E,MAAM,aAAa,GAA2B;IAC5C,gBAAgB,EAAE,kCAAkC;IACpD,YAAY,EAAM,kCAAkC;CACrD,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,MAAqC;IACrE,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAEhE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,MAAM,EAAC,QAAQ,EAAC,GAAG,MAAM,CAAC,QAAQ,CAAC;YACnC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YAClF,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC,CAAC;QACF,KAAK,EAAE,CAAC;QACR,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC3C,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,eAAK,SAAS,EAAC,eAAe,aAC3B,SAAS,IAAI,CACZ,YAAG,IAAI,EAAE,SAAS,EAAE,MAAM,EAAC,QAAQ,EAAC,GAAG,EAAC,qBAAqB,EAAC,SAAS,EAAC,cAAc,EAAC,KAAK,EAAC,QAAQ,YACnG,KAAC,UAAU,KAAG,GACZ,CACL,EACD,YAAG,IAAI,EAAC,mCAAmC,EAAC,MAAM,EAAC,QAAQ,EAAC,GAAG,EAAC,qBAAqB,EAAC,SAAS,EAAC,sCAAsC,EAAC,KAAK,EAAC,WAAW,YACtJ,KAAC,aAAa,KAAG,GACf,IACA,CACP,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../theme/NavbarItem/types/ProductPicker/index.tsx"],"names":[],"mappings":"AAMA,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAgCF,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAC,KAAkB,EAAE,SAAS,EAAC,EAAE,KAAK,2CAiG3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../theme/NavbarItem/types/ProductPicker/index.tsx"],"names":[],"mappings":"AAOA,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAgCF,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAC,KAAkB,EAAE,SAAS,EAAC,EAAE,KAAK,2CA8B3E"}
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useRef, useEffect, useCallback } from 'react';
3
2
  import Link from '@docusaurus/Link';
4
3
  import clsx from 'clsx';
5
4
  import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
6
5
  import { useThemeConfig } from '@docusaurus/theme-common';
7
- const HEADER_CLASSES = ['picker-header--nf-primary', 'picker-header--nf-secondary', 'picker-header--nf-tertiary'];
6
+ import NavbarPicker from '../../NavbarPicker';
7
+ const HEADER_CLASSES = ['picker-header--nf-tertiary', 'picker-header--nf-secondary', 'picker-header--nf-primary'];
8
8
  const NF_LOGO_DEFAULT = 'https://raw.githubusercontent.com/netfoundry/branding/refs/heads/main/images/svg/icon/netfoundry-icon-color.svg';
9
9
  const buildDefaultColumns = (img, consoleLogo) => [
10
10
  {
@@ -40,52 +40,6 @@ export default function ProductPicker({ label = 'Products', className }) {
40
40
  const columns = (themeConfig?.netfoundry?.productPickerColumns ?? [])
41
41
  .map((col, i) => ({ ...col, headerClass: HEADER_CLASSES[i] ?? '' }));
42
42
  const resolvedColumns = columns.length ? columns : buildDefaultColumns(img, consoleLogo);
43
- const wrapRef = useRef(null);
44
- const hasEnteredPanel = useRef(false);
45
- const [open, setOpen] = useState(false);
46
- const close = useCallback(() => {
47
- setOpen(false);
48
- hasEnteredPanel.current = false;
49
- }, []);
50
- // Close on outside click/touch
51
- useEffect(() => {
52
- const onOutside = (e) => {
53
- if (!wrapRef.current?.contains(e.target))
54
- close();
55
- };
56
- document.addEventListener('mousedown', onOutside);
57
- document.addEventListener('touchstart', onOutside);
58
- return () => {
59
- document.removeEventListener('mousedown', onOutside);
60
- document.removeEventListener('touchstart', onOutside);
61
- };
62
- }, [close]);
63
- // Sync: close when another product picker opens
64
- useEffect(() => {
65
- const onOtherOpen = (e) => {
66
- if (e.detail.label !== label)
67
- close();
68
- };
69
- window.addEventListener('nf-picker:open', onOtherOpen);
70
- return () => window.removeEventListener('nf-picker:open', onOtherOpen);
71
- }, [label, close]);
72
- const handleTriggerEnter = useCallback(() => {
73
- hasEnteredPanel.current = false;
74
- window.dispatchEvent(new CustomEvent('nf-picker:open', { detail: { label } }));
75
- setOpen(true);
76
- }, [label]);
77
- // Stay open until user enters the panel — no timer
78
- const handleTriggerLeave = useCallback(() => { }, []);
79
- const handlePanelEnter = useCallback(() => {
80
- hasEnteredPanel.current = true;
81
- }, []);
82
- const handlePanelLeave = useCallback(() => {
83
- if (hasEnteredPanel.current)
84
- close();
85
- }, [close]);
86
- return (_jsxs("div", { ref: wrapRef, className: clsx('navbar__item', { 'nf-picker--open': open }), children: [_jsx("a", { role: "button", href: "#", "aria-haspopup": "true", "aria-expanded": open, className: clsx('navbar__link', 'nf-picker-trigger', className), onMouseEnter: handleTriggerEnter, onMouseLeave: handleTriggerLeave, onClick: e => { e.preventDefault(); setOpen(o => !o); }, onKeyDown: e => { if (e.key === 'Enter') {
87
- e.preventDefault();
88
- setOpen(o => !o);
89
- } }, children: label }), _jsx("div", { className: clsx('nf-picker-panel', { 'nf-picker-panel--hidden': !open }), onMouseDown: e => e.stopPropagation(), onMouseEnter: handlePanelEnter, onMouseLeave: handlePanelLeave, children: _jsx("div", { className: "picker-content", children: resolvedColumns.map((col, i) => (_jsxs("div", { className: "picker-column", children: [_jsx("span", { className: clsx('picker-header', col.headerClass), children: col.header }), col.links.map((link, j) => (_jsxs(Link, { to: link.to, className: "picker-link", children: [link.logo && _jsx("img", { src: link.logo, className: clsx('picker-logo', link.logoDark && 'picker-logo--light'), alt: "" }), link.logoDark && _jsx("img", { src: link.logoDark, className: "picker-logo picker-logo--dark", alt: "" }), _jsxs("div", { className: "picker-text", children: [_jsx("strong", { children: link.label }), link.description && _jsx("span", { children: link.description })] })] }, j)))] }, i))) }) })] }));
43
+ return (_jsx(NavbarPicker, { label: label, className: className, children: _jsx("div", { className: "picker-content", children: resolvedColumns.map((col, i) => (_jsxs("div", { className: "picker-column", children: [_jsx("span", { className: clsx('picker-header', col.headerClass), children: col.header }), col.links.map((link, j) => (_jsxs(Link, { to: link.to, className: "picker-link", children: [link.logo && _jsx("img", { src: link.logo, className: clsx('picker-logo', link.logoDark && 'picker-logo--light'), alt: "" }), link.logoDark && _jsx("img", { src: link.logoDark, className: "picker-logo picker-logo--dark", alt: "" }), _jsxs("div", { className: "picker-text", children: [_jsx("strong", { children: link.label }), link.description && _jsx("span", { children: link.description })] })] }, j)))] }, i))) }) }));
90
44
  }
91
45
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../theme/NavbarItem/types/ProductPicker/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../theme/NavbarItem/types/ProductPicker/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ type Props = {
2
+ label?: string;
3
+ position?: 'left' | 'right';
4
+ className?: string;
5
+ };
6
+ export default function ResourcesPicker({ label, className }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../theme/NavbarItem/types/ResourcesPicker/index.tsx"],"names":[],"mappings":"AAqDA,KAAK,KAAK,GAAG;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAC,KAAmB,EAAE,SAAS,EAAC,EAAE,KAAK,2CA4B9E"}
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Link from '@docusaurus/Link';
3
+ import { useThemeConfig } from '@docusaurus/theme-common';
4
+ import NavbarPicker from '../../NavbarPicker';
5
+ import { DiscourseIcon, YouTubeIcon } from '../../../../src/components/icons';
6
+ const NF_LOGO_DEFAULT = 'https://raw.githubusercontent.com/netfoundry/branding/refs/heads/main/images/svg/icon/netfoundry-icon-color.svg';
7
+ const OPENZITI_LOGO_DEFAULT = 'https://netfoundry.io/docs/img/openziti-sm-logo.svg';
8
+ function isLogoLink(link) {
9
+ return 'logoSrc' in link;
10
+ }
11
+ function ResourceLink({ link }) {
12
+ return (_jsxs(Link, { to: link.href, className: "picker-link", target: "_blank", rel: "noopener noreferrer", children: [isLogoLink(link) ? (_jsxs("span", { style: { position: 'relative', display: 'inline-flex', flexShrink: 0, marginRight: '0.8rem', width: 32, height: 32 }, children: [_jsx("img", { src: link.logoSrc, style: { width: 32, height: 32, objectFit: 'contain' }, alt: "" }), link.badge && (_jsx("span", { style: { position: 'absolute', bottom: -2, right: -4, width: 14, height: 14, display: 'block' }, children: link.badge }))] })) : (_jsx("span", { className: "picker-logo", children: link.icon })), _jsxs("div", { className: "picker-text", children: [_jsx("strong", { children: link.label }), _jsx("span", { children: link.description })] })] }));
13
+ }
14
+ export default function ResourcesPicker({ label = 'Resources', className }) {
15
+ const themeConfig = useThemeConfig();
16
+ const consoleLogo = themeConfig?.netfoundry?.consoleLogo ?? NF_LOGO_DEFAULT;
17
+ const openzitiLogo = themeConfig?.netfoundry?.openzitiLogo ?? OPENZITI_LOGO_DEFAULT;
18
+ const youtubeBadge = _jsx(YouTubeIcon, { width: 14, height: 14 });
19
+ const learnLinks = [
20
+ { label: 'NetFoundry Blog', description: 'Latest news, updates, and insights from NetFoundry.', href: 'https://netfoundry.io/blog/', logoSrc: consoleLogo },
21
+ { label: 'OpenZiti Tech Blog', description: 'Technical articles and community updates.', href: 'https://blog.openziti.io/', logoSrc: openzitiLogo },
22
+ ];
23
+ const communityLinks = [
24
+ { label: 'NetFoundry YouTube', description: 'Video tutorials, demos, and technical deep dives.', href: 'https://www.youtube.com/c/NetFoundry', logoSrc: consoleLogo, badge: youtubeBadge },
25
+ { label: 'OpenZiti YouTube', description: 'OpenZiti community videos and project updates.', href: 'https://www.youtube.com/openziti', logoSrc: openzitiLogo, badge: youtubeBadge },
26
+ { label: 'OpenZiti Discourse', description: 'Ask questions and connect with the community.', href: 'https://openziti.discourse.group/', icon: _jsx(DiscourseIcon, { width: 32, height: 32 }) },
27
+ ];
28
+ return (_jsx(NavbarPicker, { label: label, className: className, panelClassName: "nf-picker-panel--narrow", autoPosition: true, children: _jsxs("div", { className: "picker-column", children: [_jsx("span", { className: "picker-header picker-header--nf-primary", style: { color: 'var(--ifm-color-primary)' }, children: "Learn & Engage" }), learnLinks.map((link, i) => _jsx(ResourceLink, { link: link }, i)), _jsx("span", { className: "picker-header picker-header--nf-secondary", style: { marginTop: '0.75rem' }, children: "Community & Support" }), communityLinks.map((link, i) => _jsx(ResourceLink, { link: link }, i))] }) }));
29
+ }
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../theme/NavbarItem/types/ResourcesPicker/index.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netfoundry/docusaurus-theme",
3
- "version": "0.8.2",
3
+ "version": "0.10.0",
4
4
  "description": "NetFoundry Docusaurus theme with shared layout, footer, and styling",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -12,7 +12,7 @@
12
12
  "scripts": {
13
13
  "clean": "node scripts/clean.mjs",
14
14
  "build": "yarn clean && tsc && yarn build:css",
15
- "watch": "tsc --watch",
15
+ "watch": "node scripts/watch.mjs",
16
16
  "build:css": "node scripts/build-css.mjs",
17
17
  "test": "jest",
18
18
  "prepublishOnly": "yarn build && yarn test"
@@ -1,4 +1,6 @@
1
1
  import ProductPicker from './types/ProductPicker';
2
+ import ResourcesPicker from './types/ResourcesPicker';
3
+ import IconLinks from './types/IconLinks';
2
4
 
3
5
  // @theme-original resolves to OUR OWN file in a plugin theme (Docusaurus sets
4
6
  // both @theme and @theme-original to the plugin file). @theme-init resolves to
@@ -11,4 +13,6 @@ const ComponentTypesOrig = require('@theme-init/NavbarItem/ComponentTypes').defa
11
13
  export default {
12
14
  ...ComponentTypesOrig,
13
15
  'custom-productPicker': ProductPicker,
16
+ 'custom-resourcesPicker': ResourcesPicker,
17
+ 'custom-iconLinks': IconLinks,
14
18
  };
@@ -0,0 +1,94 @@
1
+ import React, {useState, useRef, useEffect, useCallback, ReactNode} from 'react';
2
+ import clsx from 'clsx';
3
+
4
+ type Props = {
5
+ label: string;
6
+ className?: string;
7
+ panelClassName?: string;
8
+ /** Compute left offset via getBoundingClientRect so the panel stays on-screen.
9
+ * Use this for right-side navbar items where CSS positioning would clip. */
10
+ autoPosition?: boolean;
11
+ children: ReactNode;
12
+ };
13
+
14
+ export default function NavbarPicker({label, className, panelClassName, autoPosition = false, children}: Props) {
15
+ const wrapRef = useRef<HTMLDivElement>(null);
16
+ const hasEnteredPanel = useRef(false);
17
+ const [open, setOpen] = useState(false);
18
+ const [panelLeft, setPanelLeft] = useState<number | undefined>(undefined);
19
+
20
+ const close = useCallback(() => {
21
+ setOpen(false);
22
+ hasEnteredPanel.current = false;
23
+ }, []);
24
+
25
+ // Close on outside click/touch
26
+ useEffect(() => {
27
+ const onOutside = (e: MouseEvent | TouchEvent) => {
28
+ if (!wrapRef.current?.contains(e.target as Node)) close();
29
+ };
30
+ document.addEventListener('mousedown', onOutside);
31
+ document.addEventListener('touchstart', onOutside);
32
+ return () => {
33
+ document.removeEventListener('mousedown', onOutside);
34
+ document.removeEventListener('touchstart', onOutside);
35
+ };
36
+ }, [close]);
37
+
38
+ // Close when another picker opens
39
+ useEffect(() => {
40
+ const onOtherOpen = (e: any) => {
41
+ if (e.detail.label !== label) close();
42
+ };
43
+ window.addEventListener('nf-picker:open', onOtherOpen);
44
+ return () => window.removeEventListener('nf-picker:open', onOtherOpen);
45
+ }, [label, close]);
46
+
47
+ const handleTriggerEnter = useCallback(() => {
48
+ hasEnteredPanel.current = false;
49
+ if (autoPosition && wrapRef.current) {
50
+ const rect = wrapRef.current.getBoundingClientRect();
51
+ const PANEL_MAX_WIDTH = 430;
52
+ const MARGIN = 16;
53
+ const rightEdge = rect.left + PANEL_MAX_WIDTH;
54
+ const overflow = rightEdge - (window.innerWidth - MARGIN);
55
+ setPanelLeft(overflow > 0 ? rect.left - overflow : rect.left);
56
+ }
57
+ window.dispatchEvent(new CustomEvent('nf-picker:open', {detail: {label}}));
58
+ setOpen(true);
59
+ }, [label, autoPosition]);
60
+
61
+ const handlePanelEnter = useCallback(() => { hasEnteredPanel.current = true; }, []);
62
+ const handlePanelLeave = useCallback(() => { if (hasEnteredPanel.current) close(); }, [close]);
63
+
64
+ const panelStyle = autoPosition && panelLeft !== undefined
65
+ ? {left: panelLeft, right: 'auto', transform: 'none'} as React.CSSProperties
66
+ : undefined;
67
+
68
+ return (
69
+ <div ref={wrapRef} className={clsx('navbar__item', {'nf-picker--open': open})}>
70
+ <a
71
+ role="button"
72
+ href="#"
73
+ aria-haspopup="true"
74
+ aria-expanded={open}
75
+ className={clsx('navbar__link', 'nf-picker-trigger', className)}
76
+ onMouseEnter={handleTriggerEnter}
77
+ onMouseLeave={() => {}}
78
+ onClick={e => { e.preventDefault(); setOpen(o => !o); }}
79
+ onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); setOpen(o => !o); } }}>
80
+ {label}
81
+ </a>
82
+ {open && (
83
+ <div
84
+ className={clsx('nf-picker-panel', panelClassName)}
85
+ style={panelStyle}
86
+ onMouseDown={e => e.stopPropagation()}
87
+ onMouseEnter={handlePanelEnter}
88
+ onMouseLeave={handlePanelLeave}>
89
+ {children}
90
+ </div>
91
+ )}
92
+ </div>
93
+ );
94
+ }
@@ -0,0 +1,35 @@
1
+ import React, {useState, useEffect} from 'react';
2
+ import {DiscourseIcon, GitHubIcon} from '../../../../src/components/icons';
3
+
4
+ const GITHUB_ROUTES: Record<string, string> = {
5
+ '/docs/openziti': 'https://github.com/openziti/ziti',
6
+ '/docs/zrok': 'https://github.com/openziti/zrok',
7
+ };
8
+
9
+ export default function IconLinks(_props: {position?: 'left' | 'right'}) {
10
+ const [githubUrl, setGithubUrl] = useState<string | null>(null);
11
+
12
+ useEffect(() => {
13
+ const check = () => {
14
+ const {pathname} = window.location;
15
+ const entry = Object.entries(GITHUB_ROUTES).find(([p]) => pathname.startsWith(p));
16
+ setGithubUrl(entry ? entry[1] : null);
17
+ };
18
+ check();
19
+ window.addEventListener('popstate', check);
20
+ return () => window.removeEventListener('popstate', check);
21
+ }, []);
22
+
23
+ return (
24
+ <div className="nf-icon-links">
25
+ {githubUrl && (
26
+ <a href={githubUrl} target="_blank" rel="noopener noreferrer" className="nf-icon-link" title="GitHub">
27
+ <GitHubIcon />
28
+ </a>
29
+ )}
30
+ <a href="https://openziti.discourse.group/" target="_blank" rel="noopener noreferrer" className="nf-icon-link nf-icon-link--discourse" title="Discourse">
31
+ <DiscourseIcon />
32
+ </a>
33
+ </div>
34
+ );
35
+ }
@@ -1,154 +1,88 @@
1
- import React, {useState, useRef, useEffect, useCallback} from 'react';
2
- import Link from '@docusaurus/Link';
3
- import clsx from 'clsx';
4
- import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
5
- import {useThemeConfig} from '@docusaurus/theme-common';
6
-
7
- export type PickerLink = {
8
- label: string;
9
- to: string;
10
- logo?: string;
11
- logoDark?: string;
12
- description?: string;
13
- };
14
-
15
- export type PickerColumn = {
16
- header: string;
17
- headerClass?: string;
18
- links: PickerLink[];
19
- };
20
-
21
- type Props = {
22
- label?: string;
23
- position?: 'left' | 'right';
24
- className?: string;
25
- };
26
-
27
- const HEADER_CLASSES = ['picker-header--nf-primary', 'picker-header--nf-secondary', 'picker-header--nf-tertiary'];
28
- const NF_LOGO_DEFAULT = 'https://raw.githubusercontent.com/netfoundry/branding/refs/heads/main/images/svg/icon/netfoundry-icon-color.svg';
29
-
30
- const buildDefaultColumns = (img: string, consoleLogo: string): PickerColumn[] => [
31
- {
32
- header: 'Managed Cloud',
33
- headerClass: HEADER_CLASSES[0],
34
- links: [
35
- { label: 'NetFoundry Console', to: '#', logo: consoleLogo, description: 'Cloud-managed orchestration and global fabric control.' },
36
- { label: 'Frontdoor', to: '/docs/frontdoor', logo: `${img}/frontdoor-sm-logo.svg`, description: 'Secure application access gateway.' },
37
- ],
38
- },
39
- {
40
- header: 'Open Source',
41
- headerClass: HEADER_CLASSES[1],
42
- links: [
43
- { label: 'OpenZiti', to: '/docs/openziti', logo: `${img}/openziti-sm-logo.svg`, description: 'Programmable zero-trust mesh infrastructure.' },
44
- { label: 'zrok', to: '/docs/zrok', logo: `${img}/zrok-1.0.0-rocket-purple.svg`, logoDark: `${img}/zrok-1.0.0-rocket-green.svg`, description: 'Secure peer-to-peer sharing built on OpenZiti.' },
45
- ],
46
- },
47
- {
48
- header: 'Your own infrastructure',
49
- headerClass: HEADER_CLASSES[2],
50
- links: [
51
- { label: 'Self-Hosted', to: '/docs/selfhosted', logo: `${img}/onprem-sm-logo.svg`, description: 'Deploy the full stack in your own environment.' },
52
- { label: 'zLAN', to: '/docs/zlan', logo: `${img}/zlan/zlan-logo.svg`, description: 'Zero-trust access for OT networks.' },
53
- ],
54
- },
55
- ];
56
-
57
- export default function ProductPicker({label = 'Products', className}: Props) {
58
- const {siteConfig} = useDocusaurusContext();
59
- const themeConfig = useThemeConfig() as any;
60
- const consoleLogo = themeConfig?.netfoundry?.consoleLogo ?? NF_LOGO_DEFAULT;
61
- const img = `${siteConfig.url}${siteConfig.baseUrl}img`;
62
- const columns: PickerColumn[] = (themeConfig?.netfoundry?.productPickerColumns ?? [])
63
- .map((col: any, i: number) => ({...col, headerClass: HEADER_CLASSES[i] ?? ''}));
64
- const resolvedColumns = columns.length ? columns : buildDefaultColumns(img, consoleLogo);
65
- const wrapRef = useRef<HTMLDivElement>(null);
66
- const hasEnteredPanel = useRef(false);
67
- const [open, setOpen] = useState(false);
68
-
69
- const close = useCallback(() => {
70
- setOpen(false);
71
- hasEnteredPanel.current = false;
72
- }, []);
73
-
74
- // Close on outside click/touch
75
- useEffect(() => {
76
- const onOutside = (e: MouseEvent | TouchEvent) => {
77
- if (!wrapRef.current?.contains(e.target as Node)) close();
78
- };
79
- document.addEventListener('mousedown', onOutside);
80
- document.addEventListener('touchstart', onOutside);
81
- return () => {
82
- document.removeEventListener('mousedown', onOutside);
83
- document.removeEventListener('touchstart', onOutside);
84
- };
85
- }, [close]);
86
-
87
- // Sync: close when another product picker opens
88
- useEffect(() => {
89
- const onOtherOpen = (e: any) => {
90
- if (e.detail.label !== label) close();
91
- };
92
- window.addEventListener('nf-picker:open', onOtherOpen);
93
- return () => window.removeEventListener('nf-picker:open', onOtherOpen);
94
- }, [label, close]);
95
-
96
- const handleTriggerEnter = useCallback(() => {
97
- hasEnteredPanel.current = false;
98
- window.dispatchEvent(new CustomEvent('nf-picker:open', {detail: {label}}));
99
- setOpen(true);
100
- }, [label]);
101
-
102
- // Stay open until user enters the panel — no timer
103
- const handleTriggerLeave = useCallback(() => {}, []);
104
-
105
- const handlePanelEnter = useCallback(() => {
106
- hasEnteredPanel.current = true;
107
- }, []);
108
-
109
- const handlePanelLeave = useCallback(() => {
110
- if (hasEnteredPanel.current) close();
111
- }, [close]);
112
-
113
- return (
114
- <div
115
- ref={wrapRef}
116
- className={clsx('navbar__item', {'nf-picker--open': open})}>
117
- <a
118
- role="button"
119
- href="#"
120
- aria-haspopup="true"
121
- aria-expanded={open}
122
- className={clsx('navbar__link', 'nf-picker-trigger', className)}
123
- onMouseEnter={handleTriggerEnter}
124
- onMouseLeave={handleTriggerLeave}
125
- onClick={e => { e.preventDefault(); setOpen(o => !o); }}
126
- onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); setOpen(o => !o); } }}>
127
- {label}
128
- </a>
129
- <div
130
- className={clsx('nf-picker-panel', {'nf-picker-panel--hidden': !open})}
131
- onMouseDown={e => e.stopPropagation()}
132
- onMouseEnter={handlePanelEnter}
133
- onMouseLeave={handlePanelLeave}>
134
- <div className="picker-content">
135
- {resolvedColumns.map((col, i) => (
136
- <div key={i} className="picker-column">
137
- <span className={clsx('picker-header', col.headerClass)}>{col.header}</span>
138
- {col.links.map((link, j) => (
139
- <Link key={j} to={link.to} className="picker-link">
140
- {link.logo && <img src={link.logo} className={clsx('picker-logo', link.logoDark && 'picker-logo--light')} alt="" />}
141
- {link.logoDark && <img src={link.logoDark} className="picker-logo picker-logo--dark" alt="" />}
142
- <div className="picker-text">
143
- <strong>{link.label}</strong>
144
- {link.description && <span>{link.description}</span>}
145
- </div>
146
- </Link>
147
- ))}
148
- </div>
149
- ))}
150
- </div>
151
- </div>
152
- </div>
153
- );
154
- }
1
+ import React from 'react';
2
+ import Link from '@docusaurus/Link';
3
+ import clsx from 'clsx';
4
+ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
5
+ import {useThemeConfig} from '@docusaurus/theme-common';
6
+ import NavbarPicker from '../../NavbarPicker';
7
+
8
+ export type PickerLink = {
9
+ label: string;
10
+ to: string;
11
+ logo?: string;
12
+ logoDark?: string;
13
+ description?: string;
14
+ };
15
+
16
+ export type PickerColumn = {
17
+ header: string;
18
+ headerClass?: string;
19
+ links: PickerLink[];
20
+ };
21
+
22
+ type Props = {
23
+ label?: string;
24
+ position?: 'left' | 'right';
25
+ className?: string;
26
+ };
27
+
28
+ const HEADER_CLASSES = ['picker-header--nf-tertiary', 'picker-header--nf-secondary', 'picker-header--nf-primary'];
29
+ const NF_LOGO_DEFAULT = 'https://raw.githubusercontent.com/netfoundry/branding/refs/heads/main/images/svg/icon/netfoundry-icon-color.svg';
30
+
31
+ const buildDefaultColumns = (img: string, consoleLogo: string): PickerColumn[] => [
32
+ {
33
+ header: 'Managed Cloud',
34
+ headerClass: HEADER_CLASSES[0],
35
+ links: [
36
+ { label: 'NetFoundry Console', to: '#', logo: consoleLogo, description: 'Cloud-managed orchestration and global fabric control.' },
37
+ { label: 'Frontdoor', to: '/docs/frontdoor', logo: `${img}/frontdoor-sm-logo.svg`, description: 'Secure application access gateway.' },
38
+ ],
39
+ },
40
+ {
41
+ header: 'Open Source',
42
+ headerClass: HEADER_CLASSES[1],
43
+ links: [
44
+ { label: 'OpenZiti', to: '/docs/openziti', logo: `${img}/openziti-sm-logo.svg`, description: 'Programmable zero-trust mesh infrastructure.' },
45
+ { label: 'zrok', to: '/docs/zrok', logo: `${img}/zrok-1.0.0-rocket-purple.svg`, logoDark: `${img}/zrok-1.0.0-rocket-green.svg`, description: 'Secure peer-to-peer sharing built on OpenZiti.' },
46
+ ],
47
+ },
48
+ {
49
+ header: 'Your own infrastructure',
50
+ headerClass: HEADER_CLASSES[2],
51
+ links: [
52
+ { label: 'Self-Hosted', to: '/docs/selfhosted', logo: `${img}/onprem-sm-logo.svg`, description: 'Deploy the full stack in your own environment.' },
53
+ { label: 'zLAN', to: '/docs/zlan', logo: `${img}/zlan/zlan-logo.svg`, description: 'Zero-trust access for OT networks.' },
54
+ ],
55
+ },
56
+ ];
57
+
58
+ export default function ProductPicker({label = 'Products', className}: Props) {
59
+ const {siteConfig} = useDocusaurusContext();
60
+ const themeConfig = useThemeConfig() as any;
61
+ const consoleLogo = themeConfig?.netfoundry?.consoleLogo ?? NF_LOGO_DEFAULT;
62
+ const img = `${siteConfig.url}${siteConfig.baseUrl}img`;
63
+ const columns: PickerColumn[] = (themeConfig?.netfoundry?.productPickerColumns ?? [])
64
+ .map((col: any, i: number) => ({...col, headerClass: HEADER_CLASSES[i] ?? ''}));
65
+ const resolvedColumns = columns.length ? columns : buildDefaultColumns(img, consoleLogo);
66
+
67
+ return (
68
+ <NavbarPicker label={label} className={className}>
69
+ <div className="picker-content">
70
+ {resolvedColumns.map((col, i) => (
71
+ <div key={i} className="picker-column">
72
+ <span className={clsx('picker-header', col.headerClass)}>{col.header}</span>
73
+ {col.links.map((link, j) => (
74
+ <Link key={j} to={link.to} className="picker-link">
75
+ {link.logo && <img src={link.logo} className={clsx('picker-logo', link.logoDark && 'picker-logo--light')} alt="" />}
76
+ {link.logoDark && <img src={link.logoDark} className="picker-logo picker-logo--dark" alt="" />}
77
+ <div className="picker-text">
78
+ <strong>{link.label}</strong>
79
+ {link.description && <span>{link.description}</span>}
80
+ </div>
81
+ </Link>
82
+ ))}
83
+ </div>
84
+ ))}
85
+ </div>
86
+ </NavbarPicker>
87
+ );
88
+ }