@canopy-iiif/app 0.10.5 → 0.10.7
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 +1 -1
- package/ui/dist/index.mjs +31 -6
- package/ui/dist/index.mjs.map +2 -2
- package/ui/dist/server.mjs +207 -43
- package/ui/dist/server.mjs.map +2 -2
- package/ui/styles/components/_footer.scss +2 -3
- package/ui/styles/components/_layout.scss +69 -0
- package/ui/styles/components/_sub-navigation.scss +62 -19
- package/ui/styles/components/header/_header.scss +7 -9
- package/ui/styles/components/index.scss +1 -0
- package/ui/styles/index.css +130 -30
package/ui/dist/server.mjs
CHANGED
|
@@ -179,13 +179,38 @@ var Image = (props) => {
|
|
|
179
179
|
} catch (_) {
|
|
180
180
|
json = "{}";
|
|
181
181
|
}
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
const {
|
|
183
|
+
height = `600px`,
|
|
184
|
+
backgroundColor = `var(--color-gray-200)`,
|
|
185
|
+
caption
|
|
186
|
+
} = props || {};
|
|
187
|
+
return /* @__PURE__ */ React5.createElement(
|
|
188
|
+
"figure",
|
|
184
189
|
{
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
style: {
|
|
191
|
+
margin: `1.618rem 0 2.618rem`
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
/* @__PURE__ */ React5.createElement(
|
|
195
|
+
"div",
|
|
196
|
+
{
|
|
197
|
+
"data-canopy-image": "1",
|
|
198
|
+
style: {
|
|
199
|
+
height,
|
|
200
|
+
backgroundColor,
|
|
201
|
+
borderRadius: `0.25rem`
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
/* @__PURE__ */ React5.createElement(
|
|
205
|
+
"script",
|
|
206
|
+
{
|
|
207
|
+
type: "application/json",
|
|
208
|
+
dangerouslySetInnerHTML: { __html: json }
|
|
209
|
+
}
|
|
210
|
+
)
|
|
211
|
+
),
|
|
212
|
+
caption && /* @__PURE__ */ React5.createElement("figcaption", null, caption)
|
|
213
|
+
);
|
|
189
214
|
}
|
|
190
215
|
return /* @__PURE__ */ React5.createElement(CloverImage, { ...props });
|
|
191
216
|
};
|
|
@@ -587,9 +612,13 @@ import navigationHelpers2 from "@canopy-iiif/app/lib/components/navigation.js";
|
|
|
587
612
|
// ui/src/layout/ContentNavigation.jsx
|
|
588
613
|
import React11 from "react";
|
|
589
614
|
var SCROLL_OFFSET_REM = 1.618;
|
|
615
|
+
var MAX_HEADING_DEPTH = 3;
|
|
590
616
|
function depthIndex(depth) {
|
|
591
617
|
return Math.max(0, Math.min(5, (depth || 1) - 1));
|
|
592
618
|
}
|
|
619
|
+
function resolveDepth(value, fallback = 1) {
|
|
620
|
+
return Math.max(1, typeof value === "number" ? value : fallback);
|
|
621
|
+
}
|
|
593
622
|
function ContentNavigation({
|
|
594
623
|
items = [],
|
|
595
624
|
className = "",
|
|
@@ -602,7 +631,11 @@ function ContentNavigation({
|
|
|
602
631
|
const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
603
632
|
const savedDepthsRef = React11.useRef(null);
|
|
604
633
|
if ((!items || !items.length) && !headingId) return null;
|
|
605
|
-
const combinedClassName = [
|
|
634
|
+
const combinedClassName = [
|
|
635
|
+
"canopy-sub-navigation canopy-content-navigation",
|
|
636
|
+
"canopy-content-navigation--collapsed",
|
|
637
|
+
className
|
|
638
|
+
].filter(Boolean).join(" ");
|
|
606
639
|
const effectiveHeading = heading || pageTitle || null;
|
|
607
640
|
const navLabel = ariaLabel || (effectiveHeading ? `${effectiveHeading} navigation` : "Section navigation");
|
|
608
641
|
const getSavedDepth = React11.useCallback(
|
|
@@ -631,7 +664,11 @@ function ContentNavigation({
|
|
|
631
664
|
const id = String(node.id);
|
|
632
665
|
if (seen.has(id)) return;
|
|
633
666
|
seen.add(id);
|
|
634
|
-
const depth =
|
|
667
|
+
const depth = resolveDepth(
|
|
668
|
+
typeof node.depth === "number" ? node.depth : node.level,
|
|
669
|
+
getSavedDepth(id, 2)
|
|
670
|
+
);
|
|
671
|
+
if (depth > MAX_HEADING_DEPTH) return;
|
|
635
672
|
entries.push({ id, depth });
|
|
636
673
|
if (node.children && node.children.length) pushNodes(node.children);
|
|
637
674
|
});
|
|
@@ -747,9 +784,14 @@ function ContentNavigation({
|
|
|
747
784
|
return nodes.map((node) => {
|
|
748
785
|
if (!node) return null;
|
|
749
786
|
const id = node.id ? String(node.id) : "";
|
|
750
|
-
const depth =
|
|
787
|
+
const depth = resolveDepth(
|
|
788
|
+
typeof node.depth === "number" ? node.depth : node.level,
|
|
789
|
+
getSavedDepth(id, 2)
|
|
790
|
+
);
|
|
791
|
+
if (depth > MAX_HEADING_DEPTH) return null;
|
|
751
792
|
const idx = depthIndex(depth);
|
|
752
793
|
const isActive = id && activeId === id;
|
|
794
|
+
const childNodes = depth < MAX_HEADING_DEPTH ? renderNodes2(node.children) : null;
|
|
753
795
|
return /* @__PURE__ */ React11.createElement("li", { key: id || node.title, className: "canopy-sub-navigation__item", "data-depth": idx }, /* @__PURE__ */ React11.createElement(
|
|
754
796
|
"a",
|
|
755
797
|
{
|
|
@@ -759,19 +801,19 @@ function ContentNavigation({
|
|
|
759
801
|
"aria-current": isActive ? "location" : void 0
|
|
760
802
|
},
|
|
761
803
|
node.title
|
|
762
|
-
),
|
|
804
|
+
), childNodes ? /* @__PURE__ */ React11.createElement(
|
|
763
805
|
"ul",
|
|
764
806
|
{
|
|
765
807
|
className: "canopy-sub-navigation__list canopy-sub-navigation__list--nested",
|
|
766
808
|
role: "list"
|
|
767
809
|
},
|
|
768
|
-
|
|
810
|
+
childNodes
|
|
769
811
|
) : null);
|
|
770
812
|
});
|
|
771
813
|
},
|
|
772
814
|
[handleAnchorClick, activeId, getSavedDepth]
|
|
773
815
|
);
|
|
774
|
-
const nestedItems = renderNodes2(items);
|
|
816
|
+
const nestedItems = React11.useMemo(() => renderNodes2(items), [items, renderNodes2]);
|
|
775
817
|
const topLink = headingId ? /* @__PURE__ */ React11.createElement("li", { className: "canopy-sub-navigation__item", "data-depth": 0 }, /* @__PURE__ */ React11.createElement(
|
|
776
818
|
"a",
|
|
777
819
|
{
|
|
@@ -789,7 +831,32 @@ function ContentNavigation({
|
|
|
789
831
|
},
|
|
790
832
|
nestedItems
|
|
791
833
|
) : null) : null;
|
|
792
|
-
return /* @__PURE__ */ React11.createElement(
|
|
834
|
+
return /* @__PURE__ */ React11.createElement(
|
|
835
|
+
"nav",
|
|
836
|
+
{
|
|
837
|
+
className: combinedClassName,
|
|
838
|
+
style,
|
|
839
|
+
"aria-label": navLabel,
|
|
840
|
+
"data-canopy-content-nav": "true"
|
|
841
|
+
},
|
|
842
|
+
/* @__PURE__ */ React11.createElement(
|
|
843
|
+
"button",
|
|
844
|
+
{
|
|
845
|
+
type: "button",
|
|
846
|
+
className: "canopy-content-navigation__toggle",
|
|
847
|
+
"aria-expanded": "false",
|
|
848
|
+
"aria-label": "Show section navigation",
|
|
849
|
+
title: "Show section navigation",
|
|
850
|
+
"data-canopy-content-nav-toggle": "true",
|
|
851
|
+
"data-show-label": "Show",
|
|
852
|
+
"data-hide-label": "Hide",
|
|
853
|
+
"data-show-full-label": "Show section navigation",
|
|
854
|
+
"data-hide-full-label": "Hide section navigation"
|
|
855
|
+
},
|
|
856
|
+
"Show"
|
|
857
|
+
),
|
|
858
|
+
/* @__PURE__ */ React11.createElement("ul", { className: "canopy-sub-navigation__list", role: "list" }, topLink || nestedItems)
|
|
859
|
+
);
|
|
793
860
|
}
|
|
794
861
|
|
|
795
862
|
// ui/src/layout/Layout.jsx
|
|
@@ -828,6 +895,106 @@ function buildNavigationAside(sidebar, className) {
|
|
|
828
895
|
}
|
|
829
896
|
return sidebar;
|
|
830
897
|
}
|
|
898
|
+
function ContentNavigationScript() {
|
|
899
|
+
const code = `
|
|
900
|
+
(function () {
|
|
901
|
+
if (typeof window === 'undefined') return;
|
|
902
|
+
if (window.__CANOPY_CONTENT_NAV_READY__) return;
|
|
903
|
+
window.__CANOPY_CONTENT_NAV_READY__ = true;
|
|
904
|
+
var STORAGE_KEY = 'canopy_content_nav_collapsed';
|
|
905
|
+
var storage = null;
|
|
906
|
+
try {
|
|
907
|
+
storage = window.localStorage;
|
|
908
|
+
} catch (error) {
|
|
909
|
+
storage = null;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
function setStored(value) {
|
|
913
|
+
if (!storage) return;
|
|
914
|
+
try {
|
|
915
|
+
if (value == null) {
|
|
916
|
+
storage.removeItem(STORAGE_KEY);
|
|
917
|
+
} else {
|
|
918
|
+
storage.setItem(STORAGE_KEY, value);
|
|
919
|
+
}
|
|
920
|
+
} catch (error) {}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function getStored() {
|
|
924
|
+
if (!storage) return null;
|
|
925
|
+
try {
|
|
926
|
+
return storage.getItem(STORAGE_KEY);
|
|
927
|
+
} catch (error) {
|
|
928
|
+
return null;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
function ready(fn) {
|
|
933
|
+
if (!fn) return;
|
|
934
|
+
if (document.readyState === 'loading') {
|
|
935
|
+
document.addEventListener('DOMContentLoaded', fn, { once: true });
|
|
936
|
+
} else {
|
|
937
|
+
fn();
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
function applyState(root, collapsed) {
|
|
942
|
+
if (!root) return;
|
|
943
|
+
var isCollapsed = !!collapsed;
|
|
944
|
+
root.classList.toggle('is-collapsed', isCollapsed);
|
|
945
|
+
var layout = root.closest('.canopy-layout');
|
|
946
|
+
if (layout) layout.classList.toggle('canopy-layout--content-nav-collapsed', isCollapsed);
|
|
947
|
+
var nav = root.querySelector('[data-canopy-content-nav]');
|
|
948
|
+
if (nav) nav.classList.toggle('canopy-content-navigation--collapsed', isCollapsed);
|
|
949
|
+
var toggle = root.querySelector('[data-canopy-content-nav-toggle]');
|
|
950
|
+
if (toggle) {
|
|
951
|
+
var showLabel = toggle.getAttribute('data-show-label') || 'Show';
|
|
952
|
+
var hideLabel = toggle.getAttribute('data-hide-label') || 'Hide';
|
|
953
|
+
var showFull = toggle.getAttribute('data-show-full-label') || 'Show section navigation';
|
|
954
|
+
var hideFull = toggle.getAttribute('data-hide-full-label') || 'Hide section navigation';
|
|
955
|
+
toggle.textContent = isCollapsed ? showLabel : hideLabel;
|
|
956
|
+
toggle.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');
|
|
957
|
+
toggle.setAttribute('aria-label', isCollapsed ? showFull : hideFull);
|
|
958
|
+
toggle.setAttribute('title', isCollapsed ? showFull : hideFull);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
ready(function () {
|
|
963
|
+
var roots = Array.prototype.slice.call(
|
|
964
|
+
document.querySelectorAll('[data-canopy-content-nav-root]')
|
|
965
|
+
);
|
|
966
|
+
if (!roots.length) return;
|
|
967
|
+
var stored = getStored();
|
|
968
|
+
var collapsed = true;
|
|
969
|
+
if (stored === '0' || stored === 'false') {
|
|
970
|
+
collapsed = false;
|
|
971
|
+
} else if (stored === '1' || stored === 'true') {
|
|
972
|
+
collapsed = true;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
function sync(next) {
|
|
976
|
+
collapsed = !!next;
|
|
977
|
+
roots.forEach(function (root) {
|
|
978
|
+
applyState(root, collapsed);
|
|
979
|
+
});
|
|
980
|
+
setStored(collapsed ? '1' : '0');
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
sync(collapsed);
|
|
984
|
+
|
|
985
|
+
roots.forEach(function (root) {
|
|
986
|
+
var toggle = root.querySelector('[data-canopy-content-nav-toggle]');
|
|
987
|
+
if (!toggle) return;
|
|
988
|
+
toggle.addEventListener('click', function (event) {
|
|
989
|
+
event.preventDefault();
|
|
990
|
+
sync(!collapsed);
|
|
991
|
+
});
|
|
992
|
+
});
|
|
993
|
+
});
|
|
994
|
+
})();
|
|
995
|
+
`;
|
|
996
|
+
return /* @__PURE__ */ React12.createElement("script", { dangerouslySetInnerHTML: { __html: code } });
|
|
997
|
+
}
|
|
831
998
|
function Layout({
|
|
832
999
|
children,
|
|
833
1000
|
sidebar,
|
|
@@ -866,44 +1033,41 @@ function Layout({
|
|
|
866
1033
|
);
|
|
867
1034
|
const showLeftColumn = navigation !== false;
|
|
868
1035
|
const hasContentNavigation = navigation !== false && contentNavigation !== false && headingTree.length > 0;
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
if (showLeftColumn) {
|
|
874
|
-
return "md:grid md:grid-cols-[17rem_minmax(0,1fr)] md:items-start md:gap-10";
|
|
875
|
-
}
|
|
1036
|
+
const containerClassName = (() => {
|
|
1037
|
+
const classes = ["canopy-layout"];
|
|
1038
|
+
classes.push(fluid ? "canopy-layout--fluid" : "canopy-layout--fixed");
|
|
1039
|
+
if (showLeftColumn) classes.push("canopy-layout--with-sidebar");
|
|
876
1040
|
if (hasContentNavigation) {
|
|
877
|
-
|
|
1041
|
+
classes.push("canopy-layout--with-content-nav");
|
|
1042
|
+
classes.push("canopy-layout--content-nav-collapsed");
|
|
878
1043
|
}
|
|
879
|
-
|
|
1044
|
+
if (className) classes.push(className);
|
|
1045
|
+
return classes.join(" ");
|
|
880
1046
|
})();
|
|
881
|
-
const
|
|
882
|
-
|
|
883
|
-
gridClass,
|
|
884
|
-
fluid ? "px-4 md:px-8 lg:px-12" : "mx-auto max-w-content px-4",
|
|
885
|
-
className
|
|
886
|
-
].filter(Boolean).join(" ");
|
|
887
|
-
const leftAsideClassName = [
|
|
888
|
-
"mt-8 md:mt-0 md:order-1 md:sticky md:top-24 md:max-h-[calc(100vh-6rem)] md:overflow-y-auto text-slate-600",
|
|
889
|
-
sidebarClassName
|
|
890
|
-
].filter(Boolean).join(" ");
|
|
891
|
-
const contentOrderClass = showLeftColumn ? "md:order-2" : hasContentNavigation ? "md:order-1" : "";
|
|
892
|
-
const contentClassNames = ["space-y-6", contentOrderClass, contentClassName].filter(Boolean).join(" ");
|
|
1047
|
+
const leftAsideClassName = ["canopy-layout__sidebar", sidebarClassName].filter(Boolean).join(" ");
|
|
1048
|
+
const contentClassNames = ["canopy-layout__content", contentClassName].filter(Boolean).join(" ");
|
|
893
1049
|
const contentNavigationAsideClassName = [
|
|
894
|
-
"
|
|
1050
|
+
"canopy-layout__content-nav",
|
|
1051
|
+
"is-collapsed",
|
|
895
1052
|
contentNavigationClassName
|
|
896
1053
|
].filter(Boolean).join(" ");
|
|
897
1054
|
const sidebarNode = showLeftColumn ? buildNavigationAside(sidebar, sidebarClassName) : null;
|
|
898
|
-
return /* @__PURE__ */ React12.createElement("div", { className: containerClassName, ...rest }, showLeftColumn ? /* @__PURE__ */ React12.createElement("aside", { className: leftAsideClassName }, sidebarNode) : null, /* @__PURE__ */ React12.createElement("div", { className: contentClassNames }, children), hasContentNavigation ? /* @__PURE__ */ React12.createElement(
|
|
899
|
-
|
|
1055
|
+
return /* @__PURE__ */ React12.createElement("div", { className: containerClassName, ...rest }, showLeftColumn ? /* @__PURE__ */ React12.createElement("aside", { className: leftAsideClassName }, sidebarNode) : null, /* @__PURE__ */ React12.createElement("div", { className: contentClassNames }, children), hasContentNavigation ? /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
|
|
1056
|
+
"aside",
|
|
900
1057
|
{
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1058
|
+
className: contentNavigationAsideClassName,
|
|
1059
|
+
"data-canopy-content-nav-root": "true"
|
|
1060
|
+
},
|
|
1061
|
+
/* @__PURE__ */ React12.createElement(
|
|
1062
|
+
ContentNavigation,
|
|
1063
|
+
{
|
|
1064
|
+
items: headingTree,
|
|
1065
|
+
heading: contentHeading || void 0,
|
|
1066
|
+
headingId: headingAnchorId || void 0,
|
|
1067
|
+
pageTitle: context && context.page ? context.page.title : void 0
|
|
1068
|
+
}
|
|
1069
|
+
)
|
|
1070
|
+
), /* @__PURE__ */ React12.createElement(ContentNavigationScript, null)) : null);
|
|
907
1071
|
}
|
|
908
1072
|
|
|
909
1073
|
// ui/src/layout/CanopyHeader.jsx
|