Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

filter-cards.ts 4.8 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  1. function matchCardBySearch(card: HTMLElement, searchString: string) {
  2. const matchReg = new RegExp(searchString, 'i')
  3. // Check if this card matches - any `data-*` attribute contains the string
  4. return Object.keys(card.dataset).some((key) => matchReg.test(card.dataset[key] || ''))
  5. }
  6. function matchCardByAttribute(card: HTMLElement, attribute: string, value: string): boolean {
  7. if (attribute in card.dataset) {
  8. const allValues = (card.dataset[attribute] || '').split(',')
  9. return allValues.some((key) => key === value)
  10. }
  11. return false
  12. }
  13. export default function cardsFilter() {
  14. const inputFilter = document.querySelector('.js-filter-card-filter') as HTMLInputElement
  15. const dropdownFilters = Array.from(
  16. document.querySelectorAll('.js-filter-card-filter-dropdown')
  17. ) as Array<HTMLSelectElement>
  18. const cards = Array.from(document.querySelectorAll('.js-filter-card')) as Array<HTMLElement>
  19. const showMoreButton = document.querySelector('.js-filter-card-show-more') as HTMLButtonElement
  20. const noResults = document.querySelector('.js-filter-card-no-results') as HTMLElement
  21. // if jsFilterCardMax not set, assume no limit (well, at 99)
  22. // some landing pages don't include the button because the number of
  23. // guides is less than the max defined in includes/article-cards.html
  24. const maxCards = parseInt(showMoreButton?.dataset?.jsFilterCardMax || '') || 99
  25. const noFilter = () => {
  26. if (showMoreButton) showMoreButton.classList.remove('d-none')
  27. for (let index = 0; index < cards.length; index++) {
  28. const card = cards[index]
  29. // Hide all but the first n number of cards
  30. if (index > maxCards - 1) {
  31. card.classList.add('d-none')
  32. } else {
  33. card.classList.remove('d-none')
  34. }
  35. }
  36. }
  37. const filterEventHandler = (evt: Event) => {
  38. const currentTarget = evt.currentTarget as HTMLSelectElement | HTMLInputElement
  39. const value = currentTarget.value
  40. if (showMoreButton) showMoreButton.classList.add('d-none')
  41. // Track whether or not we had at least one match
  42. let hasMatches = false
  43. for (let index = 0; index < cards.length; index++) {
  44. const card = cards[index] as HTMLElement
  45. let cardMatches = false
  46. if (currentTarget.tagName === 'INPUT') {
  47. // Filter was emptied
  48. if (!value) {
  49. noFilter()
  50. // return hasMatches = true, so we don't show the "No results" blurb
  51. hasMatches = true
  52. continue
  53. }
  54. cardMatches = matchCardBySearch(card, value)
  55. }
  56. if (currentTarget.tagName === 'SELECT' && currentTarget.name) {
  57. const matches: Array<boolean> = []
  58. // check all the other dropdowns
  59. dropdownFilters.forEach(({ name, value }) => {
  60. if (!name || !value) return
  61. matches.push(matchCardByAttribute(card, name, value))
  62. })
  63. // if none of the filters is selected
  64. if (matches.length === 0) {
  65. noFilter()
  66. // return hasMatches = true, so we don't show the "No results" blurb
  67. hasMatches = true
  68. continue
  69. }
  70. cardMatches = matches.every((value) => value)
  71. }
  72. if (cardMatches) {
  73. card.classList.remove('d-none')
  74. hasMatches = true
  75. } else {
  76. card.classList.add('d-none')
  77. }
  78. }
  79. // If there wasn't at least one match, show the "no results" text
  80. if (!hasMatches) {
  81. noResults?.classList.remove('d-none')
  82. } else {
  83. noResults?.classList.add('d-none')
  84. }
  85. return hasMatches
  86. }
  87. if (inputFilter) {
  88. inputFilter.addEventListener('keyup', (evt) => {
  89. const hasMatches = filterEventHandler(evt)
  90. if (!hasMatches) {
  91. const cardValueEl = document.querySelector('.js-filter-card-value')
  92. if (cardValueEl) cardValueEl.textContent = (evt.currentTarget as HTMLInputElement)?.value
  93. }
  94. })
  95. }
  96. if (dropdownFilters) {
  97. dropdownFilters.forEach((filter) => filter.addEventListener('change', filterEventHandler))
  98. }
  99. if (showMoreButton) {
  100. showMoreButton.addEventListener('click', (evt: MouseEvent) => {
  101. // Number of cards that are currently visible
  102. const numShown = cards.filter((card) => !card.classList.contains('d-none')).length
  103. // We want to show n more cards
  104. const totalToShow = numShown + maxCards
  105. for (let index = numShown; index < cards.length; index++) {
  106. const card = cards[index]
  107. // If the card we're at is less than the total number of cards
  108. // we should show, show this one
  109. if (index < totalToShow) {
  110. card.classList.remove('d-none')
  111. } else {
  112. // Otherwise, we've shown the ones we intend to so exit the loop
  113. break
  114. }
  115. }
  116. // They're all shown now, we should hide the button
  117. if (totalToShow >= cards.length) {
  118. ;(evt?.currentTarget as HTMLElement)?.classList.add('d-none')
  119. }
  120. })
  121. }
  122. }
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...