v0.3: Extension #3
@ -1,30 +1,80 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import "../style/search.scss";
|
import "../style/search.scss";
|
||||||
|
import Sugestion from "./Sugestion";
|
||||||
|
import { Suggestion, SuggestionType } from "../types/suggestion";
|
||||||
|
import getGoogleSuggestions from "../functions/getGoogleSuggestions";
|
||||||
|
|
||||||
class Search extends React.Component {
|
interface State {
|
||||||
|
sugestions: Suggestion[];
|
||||||
|
}
|
||||||
|
|
||||||
|
class Search extends React.Component<{}, State> {
|
||||||
|
|
||||||
private searchInput = React.createRef<HTMLInputElement>()
|
private searchInput = React.createRef<HTMLInputElement>()
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
sugestions: []
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleQuery(query: string) {
|
handleQuery(query: string) {
|
||||||
this.search(query);
|
this.search(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
search(query: string){
|
search(query: string) {
|
||||||
const url = new URL("https://duckduckgo.com/");
|
const url = new URL("https://duckduckgo.com/");
|
||||||
const param = new URLSearchParams();
|
const param = new URLSearchParams();
|
||||||
param.append("q",query);
|
param.append("q", query);
|
||||||
url.search = param.toString();
|
url.search = param.toString();
|
||||||
window.location.href = url.toString();
|
window.location.href = url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown(event: React.KeyboardEvent) {
|
async sugest(input: string) {
|
||||||
|
if (input === "") {
|
||||||
|
this.setState({
|
||||||
|
sugestions: []
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const results = await getGoogleSuggestions(input);
|
||||||
|
|
||||||
|
const newSuggestionState: Suggestion[] = results.suggestions.map((e) => {
|
||||||
|
return {
|
||||||
|
display: e,
|
||||||
|
type: SuggestionType.QUERY
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
sugestions: newSuggestionState
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
this.handleQuery(this.searchInput.current.value);
|
this.handleQuery(this.searchInput.current.value);
|
||||||
|
} else if (event.key === "ArrowDown") {
|
||||||
|
console.log("down");
|
||||||
|
} else if (event.key === "ArrowUp") {
|
||||||
|
console.log("up");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange() {
|
||||||
|
this.sugest(this.searchInput.current.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSugestionClick(e: Suggestion) {
|
||||||
|
if (e.type === SuggestionType.QUERY) {
|
||||||
|
this.search(e.display);
|
||||||
|
} else {
|
||||||
|
window.location.href = e.url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,9 +82,21 @@ class Search extends React.Component {
|
|||||||
return <div className="search-component" >
|
return <div className="search-component" >
|
||||||
<input type="text"
|
<input type="text"
|
||||||
autoFocus
|
autoFocus
|
||||||
onKeyDown={(e)=>this.onKeyDown(e)}
|
onKeyDown={(e) => this.onKeyDown(e)}
|
||||||
|
onChange={() => this.onChange()}
|
||||||
ref={this.searchInput}
|
ref={this.searchInput}
|
||||||
/>
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="suggestion-area">
|
||||||
|
{this.state.sugestions.map((e) => {
|
||||||
|
return <Sugestion
|
||||||
|
key={e.display}
|
||||||
|
suggestion={e}
|
||||||
|
onClick={() => { this.onSugestionClick(e); }}
|
||||||
|
/>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
src/components/Sugestion.tsx
Normal file
17
src/components/Sugestion.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import "../style/suggestion.scss";
|
||||||
|
import { Suggestion } from "../types/suggestion";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
suggestion: Suggestion;
|
||||||
|
onClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Sugestion = (props: Props) => {
|
||||||
|
return <div className="suggestion-component" onClick={props.onClick}>
|
||||||
|
{props.suggestion.display}
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Sugestion;
|
17
src/functions/getGoogleSuggestions.ts
Normal file
17
src/functions/getGoogleSuggestions.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import GoogleSuggestions from "../types/GoogleSuggestions";
|
||||||
|
|
||||||
|
export default async (query: string): Promise<GoogleSuggestions> => {
|
||||||
|
const url = new URL(" http://suggestqueries.google.com/complete/search");
|
||||||
|
const param = new URLSearchParams();
|
||||||
|
param.append("q", query);
|
||||||
|
param.append("client", "firefox"); // TODO check if the result are different on different clients
|
||||||
|
url.search = param.toString();
|
||||||
|
|
||||||
|
const response = await fetch(url.toString());
|
||||||
|
const results = await response.json();
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: results[0],
|
||||||
|
suggestions: results[1]
|
||||||
|
};
|
||||||
|
};
|
@ -1,12 +1,19 @@
|
|||||||
.search-component{
|
.search-component{
|
||||||
|
|
||||||
text-align: center;
|
margin: 2em auto 2em auto;
|
||||||
margin-top: 2em;
|
width: 50%;
|
||||||
margin-bottom: 2em;
|
position: relative;
|
||||||
|
|
||||||
input[type=text]{
|
input[type=text]{
|
||||||
width: 40%;
|
width: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0.5em 1.5em;
|
padding: 0.5em 1em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.suggestion-area{
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
12
src/style/suggestion.scss
Normal file
12
src/style/suggestion.scss
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.suggestion-component{
|
||||||
|
padding: 0.2em 1em;
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
border: 1px solid #d4d4d4;
|
||||||
|
border-top: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #d4d4d4;
|
||||||
|
}
|
||||||
|
}
|
31
src/types/GoogleSuggestions.ts
Normal file
31
src/types/GoogleSuggestions.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Example if client == chrome:
|
||||||
|
[
|
||||||
|
"hello w",
|
||||||
|
["hello world","hello world anime","hello world java","hello world c","hello world python","hello world html","hello world mhw","hello welcome home"],
|
||||||
|
["","","","","","","",""],
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
"google:clientdata":{"bpc":false,"tlw":false},
|
||||||
|
"google:suggestrelevance":[1250,1050,850,700,601,600,551,550],
|
||||||
|
"google:suggesttype":["QUERY","QUERY","QUERY","QUERY","QUERY","QUERY","QUERY","QUERY"],
|
||||||
|
"google:verbatimrelevance":851
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Example if client == firefox:
|
||||||
|
[
|
||||||
|
"hello wo",
|
||||||
|
[
|
||||||
|
"hello world","hello world anime","hello world java","hello world c","hello world python","hello world html",
|
||||||
|
"hello world mhw","hello world anime stream","hello world programm","hello world anime ger sub"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface GoogleSuggestions {
|
||||||
|
query: string;
|
||||||
|
suggestions: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GoogleSuggestions;
|
12
src/types/Suggestion.ts
Normal file
12
src/types/Suggestion.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
enum SuggestionType {
|
||||||
|
QUICK,
|
||||||
|
QUERY
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Suggestion {
|
||||||
|
display: string;
|
||||||
|
type: SuggestionType;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { SuggestionType, Suggestion };
|
Loading…
Reference in New Issue
Block a user