Skip to content

Commit ddd7ba6

Browse files
authored
Learn page filter chips are SSRd and save to url hash (#1256)
1 parent 69546b5 commit ddd7ba6

File tree

3 files changed

+75
-11
lines changed

3 files changed

+75
-11
lines changed

packages/lit-dev-content/site/css/learn-catalog.css

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,6 @@ md-chip-set {
9494
--md-sys-color-on-surface-variant: #46464f;
9595
}
9696

97-
md-chip-set:not(:defined) {
98-
/*
99-
Prevent layout shift by defining the exact height of the chip-set before the
100-
component has been defined.
101-
*/
102-
display: block;
103-
height: 32px;
104-
}
105-
10697
#chips {
10798
margin: var(--_unit);
10899
}

packages/lit-dev-content/src/components/ssr.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ import './litdev-version-selector.js';
1313
import './litdev-ripple-icon-button.js';
1414
import './litdev-aside.js';
1515
import '../components/litdev-search-modal.js';
16+
import '@material/web/chips/chip-set.js';
17+
import '@material/web/chips/filter-chip.js';

packages/lit-dev-content/src/pages/learn.ts

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,43 @@ const chipSet = document.querySelector<MdChipSet>('#chips');
2828
if (!chipSet) {
2929
throw new Error(`Internal Error: no filter chips rendered`);
3030
}
31-
chipSet.addEventListener('click', async () => {
32-
await new Promise((resolve) => setTimeout(resolve, 0)); // Wait for filter chips to be completely updated.
31+
32+
/**
33+
* Updates the URL Hash based on the current state of the filter chips. If all
34+
* chips on the page are selected, then clears the hash.
35+
*/
36+
const updateUrlFromChips = () => {
37+
const chips = Array.from(chipSet.chips as FilterChip[]);
38+
let allSelected = true;
39+
const filters = [];
40+
41+
for (const chip of chips) {
42+
if (chip.selected) {
43+
filters.push(chip.dataset.value!);
44+
} else {
45+
allSelected = false;
46+
}
47+
}
48+
49+
// Save it as a query param in the hash to prevent page reload
50+
const queryParams = new URLSearchParams(window.location.hash.slice(1) ?? '');
51+
if (allSelected) {
52+
queryParams.delete('filter');
53+
} else {
54+
queryParams.set('filter', filters.join(','));
55+
}
56+
57+
window.location.hash = queryParams.toString();
58+
};
59+
60+
const updateContentFromChips = async (updateHash = true) => {
61+
// Wait for filter chips to be completely updated.
62+
await new Promise((resolve) => setTimeout(resolve, 0));
63+
64+
if (updateHash) {
65+
updateUrlFromChips();
66+
}
67+
3368
const keepKinds = new Set(
3469
(chipSet.chips as FilterChip[])
3570
.filter((el) => el.selected)
@@ -44,4 +79,40 @@ chipSet.addEventListener('click', async () => {
4479
card.style.display =
4580
keepKinds.has(cardKind) || cardKind === 'always-show' ? 'flex' : 'none';
4681
}
82+
};
83+
84+
/**
85+
* Initialize the filter chips based on the URL hash.
86+
*/
87+
const initChipsFromURL = async (hash = window.location.hash) => {
88+
const queryParams = new URLSearchParams(hash.slice(1) ?? '');
89+
const kinds = Array.from(queryParams.get('filter')?.split(',') ?? []);
90+
91+
chipSet.chips.forEach(async (chip) => {
92+
// Wait for filter chips to be completely updated to not compete with SSR.
93+
await chip.updateComplete;
94+
const chipKind = chip.dataset.value!;
95+
(chip as FilterChip).selected =
96+
kinds.length === 0 || kinds.includes(chipKind);
97+
});
98+
};
99+
100+
// Handles forwads and back navigation between hashes
101+
window.addEventListener('hashchange', async (event: HashChangeEvent) => {
102+
await initChipsFromURL(new URL(event.newURL).hash);
103+
// Do not update hash to prevent an infinite loop.
104+
await updateContentFromChips(false);
47105
});
106+
107+
// Handles clicking a filter chip.
108+
chipSet.addEventListener('click', () => updateContentFromChips());
109+
110+
const isChipDefined = !!customElements.get('md-filter-chip');
111+
112+
if (!isChipDefined) {
113+
// Wait for SSR hydration to complete before initializing the chips.
114+
customElements.whenDefined('md-filter-chip').then(() => initChipsFromURL());
115+
} else {
116+
// Hydration has completed, initialize the chips immediately.
117+
initChipsFromURL();
118+
}

0 commit comments

Comments
 (0)