-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathsearch.html
126 lines (115 loc) · 3.08 KB
/
search.html
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
---
layout: layouts/main.html
title: Search
templateClass: tmpl-home
eleventyNavigation:
key: Search
order: 4
---
<h1>Search</h1>
<div class="search" id="search"></div>
<script src="/js/mithril.min.js"></script>
<script>
// State & Actions
const State = () => ({
formData: {
input: '',
words: []
},
rawData: [],
filteredData: [],
})
const Actions = state => ({
filter: (input) => {
state.formData.input = input
state.formData.words = splitInput(input)
if (state.formData.words.length === 0) {
state.filteredData = []
return
}
state.filteredData = filterDataByWords(
state.rawData,
state.formData.words
)
},
reset: () => {
state.formData.input = ''
state.formData.words = []
state.filteredData = []
}
})
const state = State()
const actions = Actions(state)
// Helpers
const focus = ({dom}) => setTimeout(() => dom.focus())
const filter = (e) => {
localStorage.setItem('search', e.target.value)
actions.filter(e.target.value)
}
const reset = () => {
localStorage.setItem('search', '')
actions.reset()
}
const highlight = (string, words) => {
const pattern = new RegExp(words.join('|'), 'gi')
return string.replace(pattern, (word) => {
return '<span class="search__highlighted">' + word + '</span>';
})
}
const splitInput = (input) => {
input = input.trim()
return input.length > 0 ? input.split(/\s+/) : []
}
const filterDataByWords = (data, words) => data.filter(item => {
let filtered = true
words.map(word => {
filtered &= item.title.toLowerCase().indexOf(word.toLowerCase()) > -1
})
return filtered
})
// Components
const Form = {
view: ({attrs: {state}}) => m('.search__form', [
m('input.search__input[type=text]', {
placeholder: 'e.g. component',
oncreate: focus,
onupdate: focus,
oninput: filter,
value: state.formData.input
}),
state.formData.input.length > 0
? m('button.search__reset', {onclick: reset}, 'Reset')
: ''
])
}
const List = {
view: ({attrs: {state}}) => {
return state.filteredData.length > 0
? [
m('p', state.filteredData.length + ' examples found.'),
m('ul.search__results', state.filteredData.map(example => {
return m('li.search__result', m('a.search__link', {href: example.url}, m.trust(
highlight(example.title, state.formData.words)
)))
}))
]
: state.formData.input.length > 0
? m('p', 'Your search did not match any examples.')
: m('p', 'Search here for Mithril.js examples.')
}
}
// Application
m.mount(document.getElementById('search'), {
oninit: async () => {
state.rawData = await m.request('/api/examples.json')
const input = localStorage.getItem('search') || ''
if (input.length > 0) {
actions.filter(input)
}
},
view: () => [
m(Form, {state, actions}),
m(List, {state})
]
})
</script>