@tomehq/theme 0.2.5 → 0.2.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/dist/chunk-37JI6XGT.js +1720 -0
- package/dist/chunk-BZGWSKT2.js +573 -0
- package/dist/chunk-CTPOZMMK.js +1703 -0
- package/dist/chunk-DO544M3G.js +1702 -0
- package/dist/chunk-FWBTK5TL.js +1444 -0
- package/dist/chunk-JA4PMX6M.js +1500 -0
- package/dist/chunk-JZRT4WNC.js +1441 -0
- package/dist/chunk-LIMYFTPC.js +1468 -0
- package/dist/chunk-MEP7P6A7.js +1500 -0
- package/dist/chunk-O4GH3KYX.js +1712 -0
- package/dist/chunk-OEXM3BEC.js +1702 -0
- package/dist/chunk-QCWZYABW.js +1468 -0
- package/dist/chunk-RKTT3ZEX.js +1500 -0
- package/dist/chunk-S47BRMNQ.js +1715 -0
- package/dist/chunk-UKYFJSUA.js +509 -0
- package/dist/chunk-X4VQYPKO.js +1768 -0
- package/dist/chunk-YZ3P3TNS.js +1760 -0
- package/dist/entry.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/src/Shell.tsx +63 -30
- package/src/entry.tsx +17 -0
package/dist/entry.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomehq/theme",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "Tome default theme and React app shell",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.tsx",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"./entry": "./src/entry.tsx"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@tomehq/components": "0.2.
|
|
13
|
-
"@tomehq/core": "0.2.
|
|
12
|
+
"@tomehq/components": "0.2.6",
|
|
13
|
+
"@tomehq/core": "0.2.6"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"react": "^18.0.0 || ^19.0.0",
|
package/src/Shell.tsx
CHANGED
|
@@ -331,7 +331,8 @@ export function Shell({
|
|
|
331
331
|
return window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? true;
|
|
332
332
|
});
|
|
333
333
|
|
|
334
|
-
const [
|
|
334
|
+
const [mobile, setMobile] = useState(() => typeof window !== "undefined" && window.innerWidth < 768);
|
|
335
|
+
const [sbOpen, setSb] = useState(() => typeof window !== "undefined" && window.innerWidth >= 768);
|
|
335
336
|
const [searchOpen, setSearch] = useState(false);
|
|
336
337
|
const [versionDropdownOpen, setVersionDropdown] = useState(false);
|
|
337
338
|
const [localeDropdownOpen, setLocaleDropdown] = useState(false);
|
|
@@ -340,7 +341,7 @@ export function Shell({
|
|
|
340
341
|
const isOldVersion = versioning && currentVersion && currentVersion !== versioning.current;
|
|
341
342
|
const [expanded, setExpanded] = useState<string[]>(navigation.map(n => n.section));
|
|
342
343
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
343
|
-
const [wide, setWide] = useState(
|
|
344
|
+
const [wide, setWide] = useState(() => typeof window !== "undefined" && window.innerWidth > 1100);
|
|
344
345
|
|
|
345
346
|
const preset = (config.theme?.preset || "amber") as PresetName;
|
|
346
347
|
const baseTokens = THEME_PRESETS[preset]?.[isDark ? "dark" : "light"] || THEME_PRESETS.amber.dark;
|
|
@@ -377,11 +378,24 @@ export function Shell({
|
|
|
377
378
|
}, [isDark]);
|
|
378
379
|
|
|
379
380
|
useEffect(() => {
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
381
|
+
const handleResize = () => {
|
|
382
|
+
const w = window.innerWidth;
|
|
383
|
+
setWide(w > 1100);
|
|
384
|
+
setMobile(w < 768);
|
|
385
|
+
};
|
|
386
|
+
handleResize();
|
|
387
|
+
window.addEventListener("resize", handleResize);
|
|
388
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
383
389
|
}, []);
|
|
384
390
|
|
|
391
|
+
// Lock body scroll when mobile sidebar is open
|
|
392
|
+
useEffect(() => {
|
|
393
|
+
if (mobile && sbOpen) {
|
|
394
|
+
document.body.style.overflow = "hidden";
|
|
395
|
+
return () => { document.body.style.overflow = ""; };
|
|
396
|
+
}
|
|
397
|
+
}, [mobile, sbOpen]);
|
|
398
|
+
|
|
385
399
|
useEffect(() => { contentRef.current?.scrollTo(0, 0); }, [currentPageId]);
|
|
386
400
|
|
|
387
401
|
// ── TOC: Config-based depth filtering + frontmatter opt-out ──
|
|
@@ -500,16 +514,25 @@ export function Shell({
|
|
|
500
514
|
allPages={allPages}
|
|
501
515
|
onNavigate={(id) => { onNavigate(id); setSearch(false); }}
|
|
502
516
|
onClose={() => setSearch(false)}
|
|
517
|
+
mobile={mobile}
|
|
503
518
|
/>
|
|
504
519
|
) : null}
|
|
505
520
|
|
|
506
521
|
<div style={{ display: "flex", height: "100vh" }}>
|
|
522
|
+
{/* Mobile sidebar backdrop */}
|
|
523
|
+
{mobile && sbOpen && (
|
|
524
|
+
<div onClick={() => setSb(false)} style={{
|
|
525
|
+
position: "fixed", inset: 0, zIndex: 200,
|
|
526
|
+
background: "rgba(0,0,0,0.4)", backdropFilter: "blur(2px)",
|
|
527
|
+
}} />
|
|
528
|
+
)}
|
|
507
529
|
{/* Sidebar */}
|
|
508
530
|
<aside style={{
|
|
509
531
|
width: sbOpen ? 270 : 0, minWidth: sbOpen ? 270 : 0,
|
|
510
532
|
background: "var(--sbBg)", borderRight: "1px solid var(--bd)",
|
|
511
533
|
display: "flex", flexDirection: "column",
|
|
512
534
|
transition: "width .2s, min-width .2s", overflow: "hidden",
|
|
535
|
+
...(mobile ? { position: "fixed" as const, top: 0, left: 0, bottom: 0, zIndex: 201 } : {}),
|
|
513
536
|
}}>
|
|
514
537
|
<a href="/" style={{ padding: "18px 20px", display: "flex", alignItems: "baseline", gap: 6, borderBottom: "1px solid var(--bd)", textDecoration: "none", color: "inherit" }}>
|
|
515
538
|
<span style={{ fontFamily: "var(--font-heading)", fontSize: 22, fontWeight: 700, fontStyle: "italic" }}>
|
|
@@ -519,7 +542,7 @@ export function Shell({
|
|
|
519
542
|
</a>
|
|
520
543
|
|
|
521
544
|
<div style={{ padding: "12px 14px" }}>
|
|
522
|
-
<button onClick={() => setSearch(true)} style={{
|
|
545
|
+
<button onClick={() => { setSearch(true); if (mobile) setSb(false); }} style={{
|
|
523
546
|
display: "flex", alignItems: "center", gap: 8, width: "100%",
|
|
524
547
|
background: "var(--cdBg)", border: "1px solid var(--bd)", borderRadius: 2,
|
|
525
548
|
padding: "8px 12px", cursor: "pointer", color: "var(--txM)", fontSize: 12.5,
|
|
@@ -545,7 +568,7 @@ export function Shell({
|
|
|
545
568
|
{sec.pages.map(p => {
|
|
546
569
|
const active = currentPageId === p.id;
|
|
547
570
|
return (
|
|
548
|
-
<button key={p.id} onClick={() => onNavigate(p.id)} style={{
|
|
571
|
+
<button key={p.id} onClick={() => { onNavigate(p.id); if (mobile) setSb(false); }} style={{
|
|
549
572
|
display: "flex", alignItems: "center", gap: 10, width: "100%",
|
|
550
573
|
textAlign: "left", background: "none",
|
|
551
574
|
border: "none", borderRadius: 0,
|
|
@@ -567,7 +590,7 @@ export function Shell({
|
|
|
567
590
|
<div style={{ padding: "12px 16px", borderTop: "1px solid var(--bd)", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
|
568
591
|
{/* TOM-12: Only show toggle when mode is "auto" */}
|
|
569
592
|
{themeMode === "auto" ? (
|
|
570
|
-
<button onClick={() => setDark(d => !d)} style={{ background: "none", border: "none", color: "var(--txM)", cursor: "pointer", display: "flex" }}>
|
|
593
|
+
<button aria-label={isDark ? "Switch to light mode" : "Switch to dark mode"} onClick={() => setDark(d => !d)} style={{ background: "none", border: "none", color: "var(--txM)", cursor: "pointer", display: "flex" }}>
|
|
571
594
|
{isDark ? <SunIcon /> : <MoonIcon />}
|
|
572
595
|
</button>
|
|
573
596
|
) : <div />}
|
|
@@ -580,24 +603,30 @@ export function Shell({
|
|
|
580
603
|
<div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }}>
|
|
581
604
|
{/* Header */}
|
|
582
605
|
<header style={{
|
|
583
|
-
display: "flex", alignItems: "center", gap: 12, padding: "10px 24px",
|
|
606
|
+
display: "flex", alignItems: "center", gap: mobile ? 8 : 12, padding: mobile ? "8px 12px" : "10px 24px",
|
|
584
607
|
borderBottom: "1px solid var(--bd)", background: "var(--hdBg)", backdropFilter: "blur(12px)",
|
|
585
608
|
}}>
|
|
586
|
-
<button onClick={() => setSb(!sbOpen)} style={{ background: "none", border: "none", color: "var(--txM)", cursor: "pointer", display: "flex" }}>
|
|
609
|
+
<button aria-label={sbOpen ? "Close sidebar" : "Open sidebar"} onClick={() => setSb(!sbOpen)} style={{ background: "none", border: "none", color: "var(--txM)", cursor: "pointer", display: "flex" }}>
|
|
587
610
|
{sbOpen ? <XIcon /> : <MenuIcon />}
|
|
588
611
|
</button>
|
|
589
|
-
|
|
590
|
-
{
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
612
|
+
{mobile ? (
|
|
613
|
+
<span style={{ fontSize: 13, color: "var(--ac)", fontFamily: "var(--font-code)", flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
|
|
614
|
+
{navigation.flatMap(s => s.pages).find(p => p.id === currentPageId)?.title || ""}
|
|
615
|
+
</span>
|
|
616
|
+
) : (
|
|
617
|
+
<div style={{ display: "flex", alignItems: "center", gap: 8, fontFamily: "var(--font-code)", fontSize: 11, color: "var(--txM)", letterSpacing: ".03em", flex: 1 }}>
|
|
618
|
+
{navigation.map(s => {
|
|
619
|
+
const f = s.pages.find(p => p.id === currentPageId);
|
|
620
|
+
if (!f) return null;
|
|
621
|
+
return <span key={s.section} style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
|
622
|
+
<span>{s.section}</span><ChevRight /><span style={{ color: "var(--ac)" }}>{f.title}</span>
|
|
623
|
+
</span>;
|
|
624
|
+
})}
|
|
625
|
+
</div>
|
|
626
|
+
)}
|
|
598
627
|
|
|
599
628
|
{/* Top Nav Links */}
|
|
600
|
-
{config.topNav && config.topNav.length > 0 && (
|
|
629
|
+
{config.topNav && config.topNav.length > 0 && !mobile && (
|
|
601
630
|
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
|
|
602
631
|
{config.topNav.map((link) => {
|
|
603
632
|
const isExternal = link.href.startsWith("http") || !link.href.startsWith("#");
|
|
@@ -771,8 +800,8 @@ export function Shell({
|
|
|
771
800
|
|
|
772
801
|
{/* Content + TOC */}
|
|
773
802
|
<div ref={contentRef} style={{ flex: 1, overflow: "auto", display: "flex" }}>
|
|
774
|
-
<main style={{ flex: 1, maxWidth: 760, padding: "40px 48px 80px", margin: "0 auto" }}>
|
|
775
|
-
<h1 style={{ fontFamily: "var(--font-heading)", fontSize: 38, fontWeight: 400, fontStyle: "italic", lineHeight: 1.15, marginBottom: 8 }}>
|
|
803
|
+
<main style={{ flex: 1, maxWidth: mobile ? "100%" : 760, padding: mobile ? "24px 16px 60px" : "40px 48px 80px", margin: "0 auto", minWidth: 0 }}>
|
|
804
|
+
<h1 style={{ fontFamily: "var(--font-heading)", fontSize: mobile ? 26 : 38, fontWeight: 400, fontStyle: "italic", lineHeight: 1.15, marginBottom: 8 }}>
|
|
776
805
|
{pageTitle}
|
|
777
806
|
</h1>
|
|
778
807
|
{pageDescription && <p style={{ fontSize: 16, color: "var(--tx2)", lineHeight: 1.6, marginBottom: 32 }}>{pageDescription}</p>}
|
|
@@ -794,7 +823,7 @@ export function Shell({
|
|
|
794
823
|
|
|
795
824
|
{/* TOM-48: Edit this page link + TOM-54: Last updated */}
|
|
796
825
|
{(editUrl || lastUpdated) && (
|
|
797
|
-
<div style={{ marginTop: 40, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 }}>
|
|
826
|
+
<div style={{ marginTop: 40, display: "flex", flexDirection: mobile ? "column" : "row", alignItems: mobile ? "flex-start" : "center", justifyContent: "space-between", gap: mobile ? 8 : 16 }}>
|
|
798
827
|
{editUrl && (
|
|
799
828
|
<div data-testid="edit-page-link">
|
|
800
829
|
<a
|
|
@@ -822,7 +851,7 @@ export function Shell({
|
|
|
822
851
|
)}
|
|
823
852
|
|
|
824
853
|
{/* Prev / Next */}
|
|
825
|
-
<div style={{ display: "flex", justifyContent: "space-between", marginTop: (editUrl || lastUpdated) ? 16 : 48, paddingTop: 24, borderTop: "1px solid var(--bd)", gap: 16 }}>
|
|
854
|
+
<div style={{ display: "flex", flexDirection: mobile ? "column" : "row", justifyContent: "space-between", marginTop: (editUrl || lastUpdated) ? 16 : 48, paddingTop: 24, borderTop: "1px solid var(--bd)", gap: mobile ? 12 : 16 }}>
|
|
826
855
|
{prev ? (
|
|
827
856
|
<button onClick={() => onNavigate(prev.id)} style={{
|
|
828
857
|
display: "flex", alignItems: "center", gap: 8, background: "none",
|
|
@@ -898,10 +927,11 @@ interface SearchResult {
|
|
|
898
927
|
}
|
|
899
928
|
|
|
900
929
|
// ── SEARCH MODAL (TOM-15) ────────────────────────────────
|
|
901
|
-
function SearchModal({ allPages, onNavigate, onClose }: {
|
|
930
|
+
function SearchModal({ allPages, onNavigate, onClose, mobile }: {
|
|
902
931
|
allPages: Array<{ id: string; title: string; description?: string }>;
|
|
903
932
|
onNavigate: (id: string) => void;
|
|
904
933
|
onClose: () => void;
|
|
934
|
+
mobile?: boolean;
|
|
905
935
|
}) {
|
|
906
936
|
const [q, setQ] = useState("");
|
|
907
937
|
const [results, setResults] = useState<SearchResult[]>([]);
|
|
@@ -993,12 +1023,15 @@ function SearchModal({ allPages, onNavigate, onClose }: {
|
|
|
993
1023
|
return (
|
|
994
1024
|
<div onClick={onClose} style={{
|
|
995
1025
|
position: "fixed", inset: 0, zIndex: 1000, background: "rgba(0,0,0,0.55)",
|
|
996
|
-
backdropFilter: "blur(6px)", display: "flex",
|
|
997
|
-
|
|
1026
|
+
backdropFilter: "blur(6px)", display: "flex",
|
|
1027
|
+
alignItems: mobile ? "stretch" : "flex-start",
|
|
1028
|
+
justifyContent: "center", paddingTop: mobile ? 0 : "12vh",
|
|
998
1029
|
}}>
|
|
999
1030
|
<div onClick={e => e.stopPropagation()} style={{
|
|
1000
|
-
background: "var(--sf)", border: "1px solid var(--bd)", borderRadius: 2,
|
|
1001
|
-
width: "100%", maxWidth: 520, boxShadow: "0 24px 80px rgba(0,0,0,0.4)",
|
|
1031
|
+
background: "var(--sf)", border: mobile ? "none" : "1px solid var(--bd)", borderRadius: mobile ? 0 : 2,
|
|
1032
|
+
width: "100%", maxWidth: mobile ? "100%" : 520, boxShadow: mobile ? "none" : "0 24px 80px rgba(0,0,0,0.4)",
|
|
1033
|
+
overflow: "hidden", display: "flex", flexDirection: "column" as const,
|
|
1034
|
+
...(mobile ? { height: "100%" } : {}),
|
|
1002
1035
|
}}>
|
|
1003
1036
|
<div style={{ display: "flex", alignItems: "center", gap: 10, padding: "14px 18px", borderBottom: "1px solid var(--bd)" }}>
|
|
1004
1037
|
<SearchIcon />
|
|
@@ -1009,7 +1042,7 @@ function SearchModal({ allPages, onNavigate, onClose }: {
|
|
|
1009
1042
|
/>
|
|
1010
1043
|
<kbd style={{ fontFamily: "var(--font-code)", fontSize: 10, color: "var(--txM)", background: "var(--cdBg)", padding: "2px 6px", borderRadius: 2, border: "1px solid var(--bd)" }}>ESC</kbd>
|
|
1011
1044
|
</div>
|
|
1012
|
-
{results.length > 0 && <div style={{ padding: 6, maxHeight: 360, overflow: "auto" }}>
|
|
1045
|
+
{results.length > 0 && <div style={{ padding: 6, maxHeight: mobile ? "none" : 360, overflow: "auto", flex: mobile ? 1 : undefined }}>
|
|
1013
1046
|
{results.map((r, i) => (
|
|
1014
1047
|
<button key={r.id + i} onClick={() => onNavigate(r.id)} style={{
|
|
1015
1048
|
display: "block", width: "100%", textAlign: "left",
|
package/src/entry.tsx
CHANGED
|
@@ -59,6 +59,15 @@ const contentStyles = `
|
|
|
59
59
|
.tome-content img { max-width: 100%; border-radius: 2px; }
|
|
60
60
|
.tome-content hr { border: none; border-top: 1px solid var(--bd); margin: 2em 0; }
|
|
61
61
|
|
|
62
|
+
/* Mobile responsive content */
|
|
63
|
+
@media (max-width: 767px) {
|
|
64
|
+
.tome-content h2 { font-size: 1.2em; margin-top: 1.5em; }
|
|
65
|
+
.tome-content h3 { font-size: 1.05em; }
|
|
66
|
+
.tome-content pre code { font-size: 12px; padding: 0.8em 1em; }
|
|
67
|
+
.tome-content table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
|
68
|
+
.tome-content blockquote { margin: 0.8em 0; }
|
|
69
|
+
}
|
|
70
|
+
|
|
62
71
|
/* Selection style */
|
|
63
72
|
::selection { background: var(--acD); color: var(--ac); }
|
|
64
73
|
|
|
@@ -88,6 +97,14 @@ const contentStyles = `
|
|
|
88
97
|
html.dark .shiki span[style*="--shiki-dark:#6A737D"] {
|
|
89
98
|
--shiki-dark: #a0aab5 !important;
|
|
90
99
|
}
|
|
100
|
+
|
|
101
|
+
/* Light mode: darken low-contrast github-light tokens for WCAG AA on --cdBg backgrounds */
|
|
102
|
+
html:not(.dark) .shiki span[style*="color:#6A737D"] { color: #57606a !important; }
|
|
103
|
+
html:not(.dark) .shiki span[style*="color:#E36209"] { color: #b35405 !important; }
|
|
104
|
+
html:not(.dark) .shiki span[style*="color:#6F42C1"] { color: #5a32a3 !important; }
|
|
105
|
+
html:not(.dark) .shiki span[style*="color:#22863A"] { color: #1a6e2e !important; }
|
|
106
|
+
html:not(.dark) .shiki span[style*="color:#D73A49"] { color: #b62324 !important; }
|
|
107
|
+
html:not(.dark) .shiki span[style*="color:#005CC5"] { color: #0349b4 !important; }
|
|
91
108
|
`;
|
|
92
109
|
|
|
93
110
|
// ── PAGE TYPES ────────────────────────────────────────────
|