diff options
Diffstat (limited to 'src/components/searcher')
-rw-r--r-- | src/components/searcher/Searcher.vue | 157 | ||||
-rw-r--r-- | src/components/searcher/Sugestion.vue | 32 |
2 files changed, 189 insertions, 0 deletions
diff --git a/src/components/searcher/Searcher.vue b/src/components/searcher/Searcher.vue new file mode 100644 index 0000000..f8dd51f --- /dev/null +++ b/src/components/searcher/Searcher.vue | |||
@@ -0,0 +1,157 @@ | |||
1 | <template> | ||
2 | <div id="searcher"> | ||
3 | <input | ||
4 | type="text" | ||
5 | v-model='search' | ||
6 | ref='input' | ||
7 | @keydown="hotkeys" | ||
8 | @blur="close()" | ||
9 | placeholder="Search!" | ||
10 | /> | ||
11 | |||
12 | <Sugestion | ||
13 | v-for="sugestion in sugestions" | ||
14 | :key="sugestion[0]" | ||
15 | :sugestion="sugestion" | ||
16 | :class="{selected: sugestion[0] === current[0]}" | ||
17 | /> | ||
18 | </div> | ||
19 | </template> | ||
20 | |||
21 | <script> | ||
22 | import CommandsService from '@/services/CommandsService' | ||
23 | import Sugestion from '@/components/searcher/Sugestion.vue' | ||
24 | |||
25 | export default { | ||
26 | data() { | ||
27 | return { | ||
28 | commands: CommandsService, | ||
29 | search: '', | ||
30 | sugestions: [], | ||
31 | current: [] | ||
32 | } | ||
33 | }, | ||
34 | |||
35 | methods: { | ||
36 | set_sugestions() { | ||
37 | const sugestions = [] | ||
38 | let is_current_set = false | ||
39 | |||
40 | Object.entries(this.commands).forEach((element) => { | ||
41 | if(element[0].startsWith(this.search) && element[1] instanceof Function) { | ||
42 | sugestions.push(element) | ||
43 | if(!is_current_set){ | ||
44 | this.current = element | ||
45 | is_current_set = true; | ||
46 | } | ||
47 | } | ||
48 | }); | ||
49 | this.sugestions = sugestions | ||
50 | }, | ||
51 | |||
52 | close() { | ||
53 | this.$emit('close') | ||
54 | }, | ||
55 | |||
56 | change_current(a=1) { | ||
57 | let index = this.sugestions.findIndex(element => element===this.current) | ||
58 | let new_current = this.sugestions[index+a] | ||
59 | |||
60 | if (new_current) this.current = new_current | ||
61 | else this.current = this.sugestions[0] | ||
62 | }, | ||
63 | |||
64 | async execute_current() { | ||
65 | let out = await this.current[1](this) | ||
66 | |||
67 | if(out instanceof Object) { | ||
68 | this.search = '' | ||
69 | this.commands = out | ||
70 | } | ||
71 | }, | ||
72 | |||
73 | hotkeys(e) { | ||
74 | switch(e.code) { | ||
75 | case 'Escape': | ||
76 | e.preventDefault() | ||
77 | this.close() | ||
78 | break | ||
79 | case 'ArrowDown': | ||
80 | e.preventDefault() | ||
81 | this.change_current(1) | ||
82 | break | ||
83 | case 'ArrowUp': | ||
84 | e.preventDefault() | ||
85 | this.change_current(-1) | ||
86 | break | ||
87 | case 'Tab': | ||
88 | e.preventDefault() | ||
89 | this.change_current(1) | ||
90 | break | ||
91 | case 'Enter': | ||
92 | e.preventDefault() | ||
93 | this.execute_current() | ||
94 | break | ||
95 | case 'ShiftLeft': | ||
96 | e.preventDefault() | ||
97 | this.commands = CommandsService | ||
98 | break | ||
99 | } | ||
100 | }, | ||
101 | }, | ||
102 | |||
103 | watch: { | ||
104 | search() { | ||
105 | this.set_sugestions() | ||
106 | }, | ||
107 | |||
108 | commands() { | ||
109 | this.set_sugestions() | ||
110 | } | ||
111 | }, | ||
112 | |||
113 | computed: { | ||
114 | |||
115 | }, | ||
116 | |||
117 | components: { | ||
118 | Sugestion | ||
119 | }, | ||
120 | |||
121 | created() { | ||
122 | this.set_sugestions() | ||
123 | |||
124 | this.$nextTick(function () { | ||
125 | this.$refs.input.focus() | ||
126 | }) | ||
127 | } | ||
128 | } | ||
129 | </script> | ||
130 | |||
131 | <style scoped> | ||
132 | #searcher { | ||
133 | position: absolute; | ||
134 | width: 30%; | ||
135 | height: 80%; | ||
136 | top: 50%; | ||
137 | left: 50%; | ||
138 | background-color: #202020; | ||
139 | padding: 20px; | ||
140 | border-radius: 10px; | ||
141 | transform: translate(-50%, -50%); | ||
142 | } | ||
143 | |||
144 | #searcher input { | ||
145 | width: 100%; | ||
146 | margin-bottom: 20px; | ||
147 | padding: 10px; | ||
148 | padding-right: 0px; | ||
149 | height: 20px; | ||
150 | border: none; | ||
151 | background-color: #303030; | ||
152 | } | ||
153 | |||
154 | .selected { | ||
155 | background-color: #505050; | ||
156 | } | ||
157 | </style> | ||
diff --git a/src/components/searcher/Sugestion.vue b/src/components/searcher/Sugestion.vue new file mode 100644 index 0000000..4721ca2 --- /dev/null +++ b/src/components/searcher/Sugestion.vue | |||
@@ -0,0 +1,32 @@ | |||
1 | <template> | ||
2 | <div class="sugestion"> | ||
3 | <span>{{sugestion[0]}}</span> | ||
4 | </div> | ||
5 | </template> | ||
6 | |||
7 | <script> | ||
8 | export default { | ||
9 | props: { | ||
10 | sugestion: Array | ||
11 | }, | ||
12 | |||
13 | created() { | ||
14 | this.$nextTick(function () { | ||
15 | }) | ||
16 | } | ||
17 | |||
18 | } | ||
19 | </script> | ||
20 | |||
21 | <style scoped> | ||
22 | .sugestion { | ||
23 | width: 100%; | ||
24 | margin-left: auto; | ||
25 | margin-right: auto; | ||
26 | background-color: #303030; | ||
27 | |||
28 | margin-top: 10px; | ||
29 | padding: 5px; | ||
30 | padding-right: 0px; | ||
31 | } | ||
32 | </style> | ||