@@ -4,7 +4,6 @@ import Layout from "../components/Layout";
44import getAppProps , { AppProps } from "../components/WithAppProps" ;
55import Link from "next/link" ;
66import { AwesomeArcadeExtensionsList } from "@/components/AwesomeArcadeList" ;
7- import { debounce } from "@/scripts/Utils/Timers" ;
87import { AnalyticEvents } from "@/components/Analytics" ;
98import { useSession } from "next-auth/react" ;
109import Tippy from "@tippyjs/react" ;
@@ -27,7 +26,9 @@ export function Extensions({
2726} : ExtensionsProps ) : React . ReactNode {
2827 const { data : session } = useSession ( ) ;
2928
30- const [ search , setSearch ] = React . useState ( "" ) ;
29+ const [ disableSearch , setDisableSearch ] = React . useState ( false ) ;
30+ const [ searchParamsChanged , setSearchParamsChanged ] = React . useState ( false ) ;
31+ const [ searchQuery , setSearchQuery ] = React . useState ( "" ) ;
3132 const [ showJSOnlyExts , setShowJSOnlyExts ] = React . useState ( false ) ;
3233 const [ filteredList , setFilteredList ] = React . useState ( list ) ;
3334 const [ resultCount , setResultCount ] = React . useState < number | undefined > (
@@ -40,84 +41,83 @@ export function Extensions({
4041 React . useEffect ( ( ) => {
4142 const q = new URLSearchParams ( window . location . search ) . get ( searchParam ) ;
4243 if ( q !== null ) {
43- setSearch ( q ) ;
44+ setSearchQuery ( q ) ;
4445 }
4546 const showJSOnly = new URLSearchParams ( window . location . search ) . get (
4647 showJSOnlyParam ,
4748 ) ;
4849 if ( showJSOnly !== null ) {
4950 setShowJSOnlyExts ( stringToBool ( showJSOnly ) ) ;
5051 }
52+ runSearch ( q , showJSOnly != null ? stringToBool ( showJSOnly ) : null ) ;
5153 if ( window . location . hash . length > 0 ) {
5254 smoothScrollToID ( window . location . hash . replace ( "#" , "" ) ) ;
5355 }
56+ // eslint-disable-next-line
5457 } , [ ] ) ;
5558
56- React . useEffect ( ( ) => {
57- const url = new URL ( window . location . toString ( ) ) ;
58- if ( search === "" ) {
59- url . searchParams . delete ( searchParam ) ;
60- } else {
61- url . searchParams . set ( searchParam , search ) ;
62- }
63- if ( showJSOnlyExts ) {
64- url . searchParams . set ( showJSOnlyParam , "true" ) ;
65- } else {
66- url . searchParams . delete ( showJSOnlyParam ) ;
67- }
68- window . history . replaceState ( { } , "" , url . toString ( ) ) ;
69- } , [ search , showJSOnlyExts ] ) ;
70-
71- // React.useEffect(() => {
72- // document.addEventListener("keydown", (e) => {
73- // if (e.keyCode === 114 || ((e.ctrlKey || e.metaKey) && e.keyCode === 70)) {
74- // e.preventDefault();
75- // }
76- // if ((e.ctrlKey || e.metaKey) && e.code == "KeyF") {
77- // setTimeout(() => {
78- // console.log("FOCUS FIND");
79- // const searchBar = getElement("searchBar") as HTMLInputElement;
80- // searchBar.focus();
81- // }, 1000);
82- // }
83- // });
84- // }, []);
85-
86- React . useEffect ( ( ) => {
87- if ( search . length > 0 || showJSOnlyExts ) {
88- const filtered = structuredClone ( list ) ;
89- let extCount = 0 ;
90- const group = filtered ;
91- const normalizeString = ( s : string ) : string => {
92- return s . trim ( ) . toLowerCase ( ) ;
93- } ;
94- const normalizedSearch = normalizeString ( search ) ;
95- for ( let i = group . length - 1 ; i >= 0 ; i -- ) {
96- const ext = group [ i ] ;
97- if (
98- ! (
99- normalizeString ( ext . repo ) . includes ( normalizedSearch ) ||
100- normalizeString ( ext . url ) . includes ( normalizedSearch ) ||
101- // normalizeString(ext.description).includes(normalizedSearch) ||
102- normalizeString ( ext . author ) . includes ( normalizedSearch )
103- ) ||
104- ( ! showJSOnlyExts && ext . javascriptOnly )
105- ) {
106- group . splice ( i , 1 ) ;
59+ const runSearch = (
60+ query : string | null = null ,
61+ showJSOnly : boolean | null = null ,
62+ ) => {
63+ setDisableSearch ( true ) ;
64+ setTimeout ( ( ) => {
65+ const q = query ?? searchQuery ;
66+ const showJS = showJSOnly ?? showJSOnlyExts ;
67+ setSearchQuery ( q ) ;
68+ setShowJSOnlyExts ( showJS ) ;
69+ if ( q . length > 0 || showJS ) {
70+ const filtered = structuredClone ( list ) ;
71+ let extCount = 0 ;
72+ const group = filtered ;
73+ const normalizeString = ( s : string ) : string => {
74+ return s . trim ( ) . toLowerCase ( ) ;
75+ } ;
76+ const normalizedSearch = normalizeString ( q ) ;
77+ for ( let i = group . length - 1 ; i >= 0 ; i -- ) {
78+ const ext = group [ i ] ;
79+ if (
80+ ! (
81+ normalizeString ( ext . repo ) . includes ( normalizedSearch ) ||
82+ normalizeString ( ext . url ) . includes ( normalizedSearch ) ||
83+ normalizeString (
84+ JSON . stringify ( ext [ "description" ] [ "children" ] ) ,
85+ ) . includes ( normalizedSearch ) ||
86+ normalizeString ( ext . author ) . includes ( normalizedSearch )
87+ ) ||
88+ ( ! showJS && ext . javascriptOnly )
89+ ) {
90+ group . splice ( i , 1 ) ;
91+ }
10792 }
93+ extCount += group . length ;
94+ setFilteredList ( filtered ) ;
95+ setResultCount ( extCount ) ;
96+ } else {
97+ setFilteredList (
98+ list . filter ( ( ext ) => {
99+ return ! ext . javascriptOnly ;
100+ } ) ,
101+ ) ;
102+ setResultCount ( undefined ) ;
108103 }
109- extCount += group . length ;
110- setFilteredList ( filtered ) ;
111- setResultCount ( extCount ) ;
112- } else {
113- setFilteredList (
114- list . filter ( ( ext ) => {
115- return ! ext . javascriptOnly ;
116- } ) ,
117- ) ;
118- setResultCount ( undefined ) ;
119- }
120- } , [ search , showJSOnlyExts , list ] ) ;
104+ const url = new URL ( window . location . toString ( ) ) ;
105+ if ( q === "" ) {
106+ url . searchParams . delete ( searchParam ) ;
107+ } else {
108+ url . searchParams . set ( searchParam , q ) ;
109+ }
110+ if ( showJS ) {
111+ url . searchParams . set ( showJSOnlyParam , "true" ) ;
112+ } else {
113+ url . searchParams . delete ( showJSOnlyParam ) ;
114+ }
115+ window . history . replaceState ( { } , "" , url . toString ( ) ) ;
116+ AnalyticEvents . sendSearch ( q ) ;
117+ setDisableSearch ( false ) ;
118+ setSearchParamsChanged ( false ) ;
119+ } ) ;
120+ } ;
121121
122122 return (
123123 < Layout
@@ -164,36 +164,49 @@ export function Extensions({
164164 }
165165 ` }
166166 </ style >
167- < Tippy content = "Search extensions by author, name, or URL!" >
167+ < Tippy content = "Search extensions by author, name, description, or URL!" >
168168 < input
169169 id = "searchBar"
170170 type = "search"
171171 className = "form-control"
172- placeholder = "Search extensions by author, name, or URL!"
173- defaultValue = { search }
174- onChange = { ( event ) => {
175- const v = event . target . value ;
176- setSearch ( v ) ;
177- debounce (
178- "extensionSearchChange" ,
179- ( ) => {
180- AnalyticEvents . sendSearch ( v ) ;
181- } ,
182- 1000 ,
183- ) ;
172+ placeholder = "Search extensions by author, name, description, or URL!"
173+ // disabled={disableSearch }
174+ value = { searchQuery }
175+ onChange = { ( e ) => {
176+ setSearchQuery ( e . target . value ) ;
177+ setSearchParamsChanged ( true ) ;
178+ } }
179+ onKeyDown = { ( e ) => {
180+ if ( e . key === "Enter" ) {
181+ runSearch ( ) ;
182+ e . currentTarget . focus ( ) ;
183+ }
184184 } }
185185 aria-label = "Search query"
186186 />
187187 </ Tippy >
188188 </ div >
189+ < div className = "col-auto" >
190+ < button
191+ type = "button"
192+ className = "btn btn-primary"
193+ disabled = { disableSearch || ! searchParamsChanged }
194+ onClick = { ( ) => {
195+ runSearch ( ) ;
196+ } }
197+ >
198+ Search
199+ </ button >
200+ </ div >
189201 < div className = "col-auto" >
190202 < div className = "form-check" >
191203 < input
192204 className = "form-check-input"
193205 type = "checkbox"
194- defaultChecked = { showJSOnlyExts }
206+ checked = { showJSOnlyExts }
195207 onChange = { ( e ) => {
196208 setShowJSOnlyExts ( e . target . checked ) ;
209+ setSearchParamsChanged ( true ) ;
197210 } }
198211 id = "showJSOnlyExtsCheckInput"
199212 />
0 commit comments