@jant/core 0.6.13 → 0.6.14
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/{app-HnzmsaqU.js → app-2i7-WQHg.js} +26 -22
- package/dist/app-DZDlmh7C.js +6 -0
- package/dist/client/.vite/manifest.json +3 -3
- package/dist/client/_assets/{client-3_OaxhTs.js → client-BvID5ucz.js} +1 -1
- package/dist/client/_assets/client-Cevfpm8H.css +2 -0
- package/dist/client/_assets/{client-auth-TsYq90xm.js → client-auth-v3yvhbgZ.js} +175 -172
- package/dist/{export-Dfbq9aot.js → export-DWn149b7.js} +14 -6
- package/dist/{github-sync-BGTLx8Mf.js → github-sync-C0zyF6XS.js} +2 -2
- package/dist/{github-sync--PSoE-Ne.js → github-sync-Ckk0sJxK.js} +1 -1
- package/dist/index.js +3 -3
- package/dist/node.js +4 -4
- package/package.json +1 -1
- package/src/client/components/__tests__/jant-command-palette.test.ts +137 -10
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +3 -0
- package/src/client/components/jant-command-palette.ts +100 -70
- package/src/client/components/jant-compose-dialog.ts +1 -1
- package/src/client/tiptap/__tests__/footnotes.test.ts +284 -0
- package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +148 -1
- package/src/client/tiptap/bubble-menu.ts +3 -3
- package/src/client/tiptap/footnotes.ts +156 -0
- package/src/client/tiptap/markdown-clipboard.ts +7 -2
- package/src/lib/__tests__/markdown-to-tiptap.test.ts +4 -0
- package/src/lib/markdown-manager.ts +14 -5
- package/src/styles/ui.css +116 -28
- package/src/ui/feed/__tests__/timeline-cards.test.ts +8 -3
- package/src/ui/layouts/BaseLayout.tsx +1 -1
- package/src/ui/layouts/SiteLayout.tsx +19 -13
- package/src/ui/layouts/__tests__/SiteLayout.test.tsx +48 -0
- package/dist/app-CWJFPjuR.js +0 -6
- package/dist/client/_assets/client-DCrcHVJl.css +0 -2
|
@@ -723,6 +723,7 @@ export function createMarkdownContentExtensions(
|
|
|
723
723
|
heading: { levels: [1, 2, 3] },
|
|
724
724
|
link: { openOnClick: false, autolink: false },
|
|
725
725
|
codeBlock: false,
|
|
726
|
+
trailingNode: { notAfter: ["footnoteDefinition"] },
|
|
726
727
|
}),
|
|
727
728
|
MarkdownCodeBlock,
|
|
728
729
|
Table.configure({
|
|
@@ -742,11 +743,19 @@ export function createMarkdownContentExtensions(
|
|
|
742
743
|
];
|
|
743
744
|
}
|
|
744
745
|
|
|
745
|
-
|
|
746
|
+
/**
|
|
747
|
+
* Normalizes Markdown parser output before it enters the editor schema.
|
|
748
|
+
*
|
|
749
|
+
* @param node - Parsed Tiptap document or descendant node
|
|
750
|
+
* @returns A normalized copy safe to load into an editor
|
|
751
|
+
* @example
|
|
752
|
+
* const normalized = normalizeMarkdownDocument(markdownManager.parse(source));
|
|
753
|
+
*/
|
|
754
|
+
export function normalizeMarkdownDocument(node: JSONContent): JSONContent {
|
|
746
755
|
const normalized: JSONContent = { ...node };
|
|
747
756
|
|
|
748
757
|
if (normalized.content) {
|
|
749
|
-
normalized.content = normalized.content.map(
|
|
758
|
+
normalized.content = normalized.content.map(normalizeMarkdownDocument);
|
|
750
759
|
}
|
|
751
760
|
|
|
752
761
|
if (normalized.marks) {
|
|
@@ -810,9 +819,9 @@ function normalizeMarkdownDoc(node: JSONContent): JSONContent {
|
|
|
810
819
|
child?.type === "text" &&
|
|
811
820
|
typeof child.text === "string" &&
|
|
812
821
|
nextChild?.type === "footnoteReference" &&
|
|
813
|
-
child.text
|
|
822
|
+
/\n[ \t]*$/.test(child.text)
|
|
814
823
|
) {
|
|
815
|
-
const trimmedText = child.text.replace(/\n
|
|
824
|
+
const trimmedText = child.text.replace(/\n[ \t]*$/, "");
|
|
816
825
|
if (trimmedText) {
|
|
817
826
|
nextContent.push({
|
|
818
827
|
...child,
|
|
@@ -854,7 +863,7 @@ export function getMarkdownManager(): MarkdownManager {
|
|
|
854
863
|
}
|
|
855
864
|
|
|
856
865
|
export function parseMarkdownDocument(markdown: string): JSONContent {
|
|
857
|
-
return
|
|
866
|
+
return normalizeMarkdownDocument(getMarkdownManager().parse(markdown));
|
|
858
867
|
}
|
|
859
868
|
|
|
860
869
|
export function serializeMarkdownDocument(doc: JSONContent): string {
|
package/src/styles/ui.css
CHANGED
|
@@ -848,7 +848,7 @@
|
|
|
848
848
|
display: flex;
|
|
849
849
|
}
|
|
850
850
|
|
|
851
|
-
.site-header-more-divider-
|
|
851
|
+
.site-header-more-divider-show-lg {
|
|
852
852
|
display: block;
|
|
853
853
|
}
|
|
854
854
|
}
|
|
@@ -865,6 +865,10 @@
|
|
|
865
865
|
.site-header-more-link-show-md {
|
|
866
866
|
display: flex;
|
|
867
867
|
}
|
|
868
|
+
|
|
869
|
+
.site-header-more-divider-show-md {
|
|
870
|
+
display: block;
|
|
871
|
+
}
|
|
868
872
|
}
|
|
869
873
|
|
|
870
874
|
@media (max-width: 580px) {
|
|
@@ -879,6 +883,10 @@
|
|
|
879
883
|
.site-header-more-link-show-sm {
|
|
880
884
|
display: flex;
|
|
881
885
|
}
|
|
886
|
+
|
|
887
|
+
.site-header-more-divider-show-sm {
|
|
888
|
+
display: block;
|
|
889
|
+
}
|
|
882
890
|
}
|
|
883
891
|
|
|
884
892
|
@media (max-width: 480px) {
|
|
@@ -5425,6 +5433,30 @@
|
|
|
5425
5433
|
color: var(--site-text-primary);
|
|
5426
5434
|
}
|
|
5427
5435
|
|
|
5436
|
+
.compose-attached-done {
|
|
5437
|
+
margin-left: auto;
|
|
5438
|
+
padding: 6px 14px;
|
|
5439
|
+
border: none;
|
|
5440
|
+
border-radius: 8px;
|
|
5441
|
+
background-color: var(--site-text-primary);
|
|
5442
|
+
color: var(--site-elevated-bg);
|
|
5443
|
+
font-size: var(--type-ui-control);
|
|
5444
|
+
font-weight: var(--fw-medium);
|
|
5445
|
+
line-height: 1.25;
|
|
5446
|
+
cursor: pointer;
|
|
5447
|
+
transition: opacity 0.15s ease;
|
|
5448
|
+
}
|
|
5449
|
+
|
|
5450
|
+
.compose-attached-done:hover {
|
|
5451
|
+
opacity: 0.82;
|
|
5452
|
+
}
|
|
5453
|
+
|
|
5454
|
+
.compose-attached-done:focus-visible {
|
|
5455
|
+
outline: 2px solid
|
|
5456
|
+
color-mix(in srgb, var(--site-text-primary) 24%, transparent);
|
|
5457
|
+
outline-offset: 2px;
|
|
5458
|
+
}
|
|
5459
|
+
|
|
5428
5460
|
.compose-attached-tiptap {
|
|
5429
5461
|
flex: 1;
|
|
5430
5462
|
min-height: 0;
|
|
@@ -5436,6 +5468,10 @@
|
|
|
5436
5468
|
min-height: 100%;
|
|
5437
5469
|
}
|
|
5438
5470
|
|
|
5471
|
+
.compose-attached-tiptap .tiptap > :first-child {
|
|
5472
|
+
margin-top: 0;
|
|
5473
|
+
}
|
|
5474
|
+
|
|
5439
5475
|
.compose-attached-tiptap::-webkit-scrollbar {
|
|
5440
5476
|
width: 3px;
|
|
5441
5477
|
}
|
|
@@ -7735,28 +7771,9 @@
|
|
|
7735
7771
|
|
|
7736
7772
|
/*
|
|
7737
7773
|
* Reply context clones feed/detail card internals into a much narrower shell.
|
|
7738
|
-
*
|
|
7739
|
-
*
|
|
7774
|
+
* Scale headings to the thread context ladder instead of the original
|
|
7775
|
+
* page/card layout.
|
|
7740
7776
|
*/
|
|
7741
|
-
.compose-reply-context-body
|
|
7742
|
-
:is(
|
|
7743
|
-
.post-detail-title,
|
|
7744
|
-
.post-detail-body,
|
|
7745
|
-
.post-body-summary,
|
|
7746
|
-
.feed-note-title,
|
|
7747
|
-
.feed-link-title,
|
|
7748
|
-
.feed-quote,
|
|
7749
|
-
.feed-quote-attribution,
|
|
7750
|
-
.feed-quote-commentary,
|
|
7751
|
-
.feed-link-domain,
|
|
7752
|
-
.feed-continue-link,
|
|
7753
|
-
[data-post-body].prose,
|
|
7754
|
-
[data-post-meta]
|
|
7755
|
-
) {
|
|
7756
|
-
width: 100%;
|
|
7757
|
-
max-width: none;
|
|
7758
|
-
}
|
|
7759
|
-
|
|
7760
7777
|
.compose-reply-context-body
|
|
7761
7778
|
:is(.post-detail-title, .feed-note-title, .feed-link-title),
|
|
7762
7779
|
.compose-reply-context-body .prose :is(h1, h2, h3, h4) {
|
|
@@ -7976,11 +7993,11 @@
|
|
|
7976
7993
|
}
|
|
7977
7994
|
|
|
7978
7995
|
.compose-thread-layout {
|
|
7979
|
-
padding-top: 0.
|
|
7996
|
+
padding-top: 0.75rem;
|
|
7980
7997
|
}
|
|
7981
7998
|
|
|
7982
7999
|
.compose-thread-layout::before {
|
|
7983
|
-
top: 0.
|
|
8000
|
+
top: 0.75rem;
|
|
7984
8001
|
}
|
|
7985
8002
|
|
|
7986
8003
|
.compose-reply-context {
|
|
@@ -8630,9 +8647,13 @@
|
|
|
8630
8647
|
}
|
|
8631
8648
|
}
|
|
8632
8649
|
|
|
8650
|
+
.command-palette-results-container {
|
|
8651
|
+
display: flex;
|
|
8652
|
+
flex-direction: column;
|
|
8653
|
+
min-height: 0;
|
|
8654
|
+
}
|
|
8655
|
+
|
|
8633
8656
|
.command-palette-results {
|
|
8634
|
-
list-style: none;
|
|
8635
|
-
margin: 0;
|
|
8636
8657
|
padding: 0.25rem 0;
|
|
8637
8658
|
max-height: 20rem;
|
|
8638
8659
|
overflow-y: auto;
|
|
@@ -8674,6 +8695,7 @@
|
|
|
8674
8695
|
.command-palette-result-body {
|
|
8675
8696
|
display: flex;
|
|
8676
8697
|
flex-direction: column;
|
|
8698
|
+
flex: 1;
|
|
8677
8699
|
gap: 0.125rem;
|
|
8678
8700
|
min-width: 0;
|
|
8679
8701
|
}
|
|
@@ -8694,6 +8716,37 @@
|
|
|
8694
8716
|
text-overflow: ellipsis;
|
|
8695
8717
|
}
|
|
8696
8718
|
|
|
8719
|
+
.command-palette-search-action {
|
|
8720
|
+
flex-shrink: 0;
|
|
8721
|
+
border-top: 1px solid var(--color-border);
|
|
8722
|
+
padding-block: 0.625rem;
|
|
8723
|
+
background-color: color-mix(
|
|
8724
|
+
in srgb,
|
|
8725
|
+
var(--color-muted) 32%,
|
|
8726
|
+
var(--compose-paper-bg)
|
|
8727
|
+
);
|
|
8728
|
+
}
|
|
8729
|
+
|
|
8730
|
+
.command-palette-search-action:hover,
|
|
8731
|
+
.command-palette-search-action.command-palette-result-selected {
|
|
8732
|
+
background-color: var(--color-accent);
|
|
8733
|
+
}
|
|
8734
|
+
|
|
8735
|
+
.command-palette-result-shortcut {
|
|
8736
|
+
flex-shrink: 0;
|
|
8737
|
+
margin-left: auto;
|
|
8738
|
+
border: 1px solid var(--color-border);
|
|
8739
|
+
border-radius: 0.25rem;
|
|
8740
|
+
padding: 0.125rem 0.375rem;
|
|
8741
|
+
background-color: var(--compose-paper-bg);
|
|
8742
|
+
color: var(--color-muted-foreground);
|
|
8743
|
+
font-family: inherit;
|
|
8744
|
+
font-size: 0.6875rem;
|
|
8745
|
+
font-weight: 500;
|
|
8746
|
+
line-height: 1.25rem;
|
|
8747
|
+
white-space: nowrap;
|
|
8748
|
+
}
|
|
8749
|
+
|
|
8697
8750
|
.command-palette-empty {
|
|
8698
8751
|
padding: 1.5rem 1rem;
|
|
8699
8752
|
text-align: center;
|
|
@@ -9799,6 +9852,7 @@
|
|
|
9799
9852
|
vertical-align: super;
|
|
9800
9853
|
color: var(--site-accent);
|
|
9801
9854
|
white-space: nowrap;
|
|
9855
|
+
cursor: pointer;
|
|
9802
9856
|
}
|
|
9803
9857
|
|
|
9804
9858
|
.compose-tiptap-body
|
|
@@ -9834,13 +9888,22 @@
|
|
|
9834
9888
|
|
|
9835
9889
|
.compose-tiptap-body
|
|
9836
9890
|
.tiptap
|
|
9837
|
-
> :not(.tiptap-footnote-definition)
|
|
9838
|
-
|
|
9891
|
+
> :not(.tiptap-footnote-definition, .ProseMirror-gapcursor)
|
|
9892
|
+
~ .tiptap-footnote-definition {
|
|
9839
9893
|
margin-top: 2rem;
|
|
9840
9894
|
padding-top: 1rem;
|
|
9841
9895
|
border-top: 1px solid var(--site-divider);
|
|
9842
9896
|
}
|
|
9843
9897
|
|
|
9898
|
+
.compose-tiptap-body
|
|
9899
|
+
.tiptap
|
|
9900
|
+
> .tiptap-footnote-definition
|
|
9901
|
+
~ .tiptap-footnote-definition {
|
|
9902
|
+
margin-top: 1rem;
|
|
9903
|
+
padding-top: 0;
|
|
9904
|
+
border-top: 0;
|
|
9905
|
+
}
|
|
9906
|
+
|
|
9844
9907
|
.compose-tiptap-body .tiptap .tiptap-footnote-definition > :first-child {
|
|
9845
9908
|
margin-top: 0;
|
|
9846
9909
|
}
|
|
@@ -12158,3 +12221,28 @@
|
|
|
12158
12221
|
);
|
|
12159
12222
|
color: color-mix(in srgb, var(--site-text-secondary) 80%, transparent);
|
|
12160
12223
|
}
|
|
12224
|
+
|
|
12225
|
+
/*
|
|
12226
|
+
* Compose reply context renders cloned feed/detail post HTML. Keep this
|
|
12227
|
+
* outside @layer components so it can override the unlayered global post-body
|
|
12228
|
+
* width rules that intentionally make normal desktop post text use the 55%
|
|
12229
|
+
* reading column.
|
|
12230
|
+
*/
|
|
12231
|
+
.compose-reply-context-body
|
|
12232
|
+
:is(
|
|
12233
|
+
.post-detail-title,
|
|
12234
|
+
.post-detail-body,
|
|
12235
|
+
.post-body-summary,
|
|
12236
|
+
.feed-note-title,
|
|
12237
|
+
.feed-link-title,
|
|
12238
|
+
.feed-quote,
|
|
12239
|
+
.feed-quote-attribution,
|
|
12240
|
+
.feed-quote-commentary,
|
|
12241
|
+
.feed-link-domain,
|
|
12242
|
+
.feed-continue-link,
|
|
12243
|
+
[data-post-body].prose,
|
|
12244
|
+
[data-post-meta]
|
|
12245
|
+
) {
|
|
12246
|
+
width: 100%;
|
|
12247
|
+
max-width: none;
|
|
12248
|
+
}
|
|
@@ -352,10 +352,15 @@ describe("timeline cards", () => {
|
|
|
352
352
|
new URL("../../../styles/ui.css", import.meta.url),
|
|
353
353
|
"utf8",
|
|
354
354
|
);
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
/\.compose-reply-context-body\s*:is\([
|
|
355
|
+
const unlayeredCssStart = uiCss.indexOf(" * Home description");
|
|
356
|
+
const resetRule = uiCss.match(
|
|
357
|
+
/\.compose-reply-context-body\s*:is\([^{}]*\[data-post-body\]\.prose[^{}]*\)\s*\{[^{}]*width:\s*100%;[^{}]*max-width:\s*none;[^{}]*\}/,
|
|
358
358
|
);
|
|
359
|
+
|
|
360
|
+
expect(unlayeredCssStart).toBeGreaterThan(0);
|
|
361
|
+
expect(resetRule?.index).toBeGreaterThan(unlayeredCssStart);
|
|
362
|
+
expect(resetRule?.[0]).toContain("width: 100%;");
|
|
363
|
+
expect(resetRule?.[0]).toContain("max-width: none;");
|
|
359
364
|
});
|
|
360
365
|
|
|
361
366
|
it("keeps link and quote attachments hidden in compact mode", () => {
|
|
@@ -434,7 +434,7 @@ export const BaseLayout: FC<PropsWithChildren<BaseLayoutProps>> = ({
|
|
|
434
434
|
responsive header layout before external CSS/JS loads */}
|
|
435
435
|
<style
|
|
436
436
|
dangerouslySetInnerHTML={{
|
|
437
|
-
__html: `.site-header-search-link,.site-header-hamburger,.site-header-more-responsive-only,.site-header-more-link-responsive,.site-header-more-divider-responsive{display:none!important}@media(max-width:1200px){.site-header-search-form{display:none!important}.site-header-search-link{display:inline-flex!important}}@media(max-width:960px){.site-header-link-collapse-lg{display:none!important}.site-header-more-responsive-only.site-header-more-tier-lg{display:inline-flex!important}.site-header-more-link-show-lg{display:flex!important}.site-header-more-divider-
|
|
437
|
+
__html: `.site-header-search-link,.site-header-hamburger,.site-header-more-responsive-only,.site-header-more-link-responsive,.site-header-more-divider-responsive{display:none!important}@media(max-width:1200px){.site-header-search-form{display:none!important}.site-header-search-link{display:inline-flex!important}}@media(max-width:960px){.site-header-link-collapse-lg{display:none!important}.site-header-more-responsive-only.site-header-more-tier-lg{display:inline-flex!important}.site-header-more-link-show-lg{display:flex!important}.site-header-more-divider-show-lg{display:block!important}}@media(max-width:780px){.site-header-link-collapse-md{display:none!important}.site-header-more-responsive-only.site-header-more-tier-md{display:inline-flex!important}.site-header-more-link-show-md{display:flex!important}.site-header-more-divider-show-md{display:block!important}}@media(max-width:580px){.site-header-link-collapse-sm{display:none!important}.site-header-more-responsive-only.site-header-more-tier-sm{display:inline-flex!important}.site-header-more-link-show-sm{display:flex!important}.site-header-more-divider-show-sm{display:block!important}}@media(max-width:480px){.site-header-nav,.site-header-more{display:none!important}.site-header-search-slot{display:flex!important}.site-header-hamburger{display:flex!important}.site-header-right{margin-left:.35rem}}`,
|
|
438
438
|
}}
|
|
439
439
|
/>
|
|
440
440
|
{themeStyle && (
|
|
@@ -134,6 +134,15 @@ function moreLinkRevealTier(idx: number): string {
|
|
|
134
134
|
return "site-header-more-link-show-lg";
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
function getResponsiveOverflowTier(
|
|
138
|
+
headerLinkCount: number,
|
|
139
|
+
): "sm" | "md" | "lg" | null {
|
|
140
|
+
if (headerLinkCount >= 5) return "lg";
|
|
141
|
+
if (headerLinkCount === 4) return "md";
|
|
142
|
+
if (headerLinkCount === 3) return "sm";
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
137
146
|
export const SiteHeader: FC<SiteHeaderProps> = ({
|
|
138
147
|
siteName,
|
|
139
148
|
links,
|
|
@@ -176,22 +185,17 @@ export const SiteHeader: FC<SiteHeaderProps> = ({
|
|
|
176
185
|
(l) => l.placement === "header" || !l.placement,
|
|
177
186
|
);
|
|
178
187
|
const moreLinks = linksWithLabels.filter((l) => l.placement === "more");
|
|
179
|
-
const
|
|
188
|
+
const responsiveOverflowTier = getResponsiveOverflowTier(headerLinks.length);
|
|
189
|
+
const hasResponsiveOverflow = responsiveOverflowTier !== null;
|
|
180
190
|
const hasSupplementalMoreLinks = moreLinks.length > 0;
|
|
181
191
|
const showMoreMenu = hasResponsiveOverflow || hasSupplementalMoreLinks;
|
|
182
192
|
|
|
183
193
|
// Decide the widest breakpoint at which the "More" button must appear
|
|
184
194
|
// when there are no supplemental links.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
} else if (headerLinks.length === 4) {
|
|
190
|
-
responsiveTierClass = "site-header-more-tier-md";
|
|
191
|
-
} else {
|
|
192
|
-
responsiveTierClass = "site-header-more-tier-sm";
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
+
const responsiveTierClass =
|
|
196
|
+
responsiveOverflowTier && !hasSupplementalMoreLinks
|
|
197
|
+
? `site-header-more-tier-${responsiveOverflowTier}`
|
|
198
|
+
: "";
|
|
195
199
|
const moreMenuClass = [
|
|
196
200
|
"site-header-more",
|
|
197
201
|
hasResponsiveOverflow && !hasSupplementalMoreLinks
|
|
@@ -297,8 +301,10 @@ export const SiteHeader: FC<SiteHeaderProps> = ({
|
|
|
297
301
|
</a>
|
|
298
302
|
);
|
|
299
303
|
})}
|
|
300
|
-
{
|
|
301
|
-
<div
|
|
304
|
+
{responsiveOverflowTier && hasSupplementalMoreLinks && (
|
|
305
|
+
<div
|
|
306
|
+
class={`site-header-more-divider site-header-more-divider-responsive site-header-more-divider-show-${responsiveOverflowTier}`}
|
|
307
|
+
/>
|
|
302
308
|
)}
|
|
303
309
|
{moreLinks.map((link) => (
|
|
304
310
|
<a
|
|
@@ -3,8 +3,24 @@ import { renderToString } from "hono/jsx/dom/server";
|
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
4
|
import { I18nProvider } from "../../../i18n/context.js";
|
|
5
5
|
import { createI18n } from "../../../i18n/i18n.js";
|
|
6
|
+
import type { NavItemView } from "../../../types.js";
|
|
6
7
|
import { SiteLayout } from "../SiteLayout.js";
|
|
7
8
|
|
|
9
|
+
function createNavItem(
|
|
10
|
+
index: number,
|
|
11
|
+
placement: NavItemView["placement"],
|
|
12
|
+
): NavItemView {
|
|
13
|
+
return {
|
|
14
|
+
id: `nav_${index}`,
|
|
15
|
+
type: "link",
|
|
16
|
+
label: `Link ${index}`,
|
|
17
|
+
url: `/link-${index}`,
|
|
18
|
+
placement,
|
|
19
|
+
isActive: false,
|
|
20
|
+
isExternal: false,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
function renderSiteLayout(
|
|
9
25
|
props: Partial<Parameters<typeof SiteLayout>[0]> = {},
|
|
10
26
|
): string {
|
|
@@ -30,6 +46,38 @@ function renderSiteLayout(
|
|
|
30
46
|
}
|
|
31
47
|
|
|
32
48
|
describe("SiteLayout", () => {
|
|
49
|
+
it.each([
|
|
50
|
+
[3, "sm"],
|
|
51
|
+
[4, "md"],
|
|
52
|
+
[5, "lg"],
|
|
53
|
+
] as const)(
|
|
54
|
+
"reveals the More divider at the first breakpoint that overflows %i header links",
|
|
55
|
+
(headerLinkCount, tier) => {
|
|
56
|
+
const headerLinks = Array.from({ length: headerLinkCount }, (_, index) =>
|
|
57
|
+
createNavItem(index, "header"),
|
|
58
|
+
);
|
|
59
|
+
const html = renderSiteLayout({
|
|
60
|
+
links: [...headerLinks, createNavItem(headerLinkCount, "more")],
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(html).toContain(
|
|
64
|
+
`class="site-header-more-divider site-header-more-divider-responsive site-header-more-divider-show-${tier}"`,
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
it("omits the More divider when no header link can overflow", () => {
|
|
70
|
+
const html = renderSiteLayout({
|
|
71
|
+
links: [
|
|
72
|
+
createNavItem(0, "header"),
|
|
73
|
+
createNavItem(1, "header"),
|
|
74
|
+
createNavItem(2, "more"),
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(html).not.toContain("site-header-more-divider");
|
|
79
|
+
});
|
|
80
|
+
|
|
33
81
|
it("renders the mobile compose FAB for authenticated timeline pages", () => {
|
|
34
82
|
const html = renderSiteLayout({
|
|
35
83
|
currentPath: "/latest",
|