@@ -13,6 +13,12 @@ import { IconButton } from "./IconButton";
1313import { createDelegate , type Delegate } from "dreamland/core" ;
1414import type { Tab } from "../Tab" ;
1515
16+ export function trimUrl ( v : URL ) {
17+ return (
18+ ( v . protocol === "puter:" ? v . protocol : "" ) + v . host + v . pathname + v . search
19+ ) ;
20+ }
21+
1622export const Spacer : Component = function ( cx ) {
1723 return < div > </ div > ;
1824} ;
@@ -22,6 +28,13 @@ Spacer.style = css`
2228 }
2329` ;
2430
31+ type OmniboxResult = {
32+ kind : "search" | "history" | "bookmark" | "direct" ;
33+ title ?: string ;
34+ url : string ;
35+ favicon ?: string | null ;
36+ } ;
37+
2538export const UrlInput : Component <
2639 {
2740 tabUrl : URL ;
@@ -34,21 +47,66 @@ export const UrlInput: Component<
3447
3548 focusindex : number ;
3649
37- overflowItems : string [ ] ;
50+ overflowItems : OmniboxResult [ ] ;
3851 }
3952> = function ( cx ) {
4053 this . focusindex = 0 ;
4154 this . overflowItems = [ ] ;
4255 this . value = "" ;
4356 const fetchSuggestions = async ( ) => {
57+ let search = this . input . value ;
58+
59+ this . overflowItems = [ ] ;
60+
61+ for ( const entry of browser . globalhistory ) {
62+ if ( ! entry . url . href . includes ( search ) && ! entry . title ?. includes ( search ) )
63+ continue ;
64+ if ( this . overflowItems . some ( ( i ) => i . url === entry . url . href ) ) continue ;
65+
66+ this . overflowItems . push ( {
67+ kind : "history" ,
68+ title : entry . title ,
69+ url : entry . url . href ,
70+ favicon : entry . favicon ,
71+ } ) ;
72+ }
73+ this . overflowItems = this . overflowItems . slice ( 0 , 5 ) ;
74+
75+ if (
76+ search . startsWith ( "http:" ) ||
77+ search . startsWith ( "https:" ) ||
78+ search . startsWith ( "puter:" )
79+ ) {
80+ this . overflowItems = [
81+ {
82+ kind : "direct" ,
83+ url : search ,
84+ } ,
85+ ...this . overflowItems ,
86+ ] ;
87+ return ;
88+ }
89+
4490 let resp = await fetch (
4591 scramjet . encodeUrl (
46- `http://suggestqueries.google.com/complete/search?client=chrome&q=${ encodeURIComponent ( this . input . value ) } `
92+ `http://suggestqueries.google.com/complete/search?client=chrome&q=${ encodeURIComponent ( search ) } `
4793 )
4894 ) ;
4995 let json = await resp . json ( ) ;
50- console . log ( json ) ;
51- this . overflowItems = json [ 1 ] . slice ( 0 , 5 ) ;
96+ for ( const item of json [ 1 ] . slice ( 0 , 5 ) ) {
97+ // it's gonna be stuff like "http //fortnite.com/2fa ps5"
98+ // these results are generally useless
99+ if ( item . startsWith ( "http" ) ) continue ;
100+
101+ this . overflowItems . push ( {
102+ kind : "search" ,
103+ title : item ,
104+ url : `https://www.google.com/search?q=${ encodeURIComponent ( item ) } ` ,
105+ favicon : scramjet . encodeUrl ( "https://www.google.com/favicon.ico" ) ,
106+ } ) ;
107+ }
108+
109+ this . overflowItems = this . overflowItems ;
52110 } ;
53111 let currentTimeout : number | null = null ;
54112 let ratelimiting = false ;
@@ -110,18 +168,23 @@ export const UrlInput: Component<
110168 < div
111169 class = "overflowitem"
112170 on :click = { ( ) => {
113- this . value = item ;
114171 this . active = false ;
115172 this . input . blur ( ) ;
116173
117- browser . searchNavigate ( this . value ) ;
174+ browser . activetab . pushNavigate ( new URL ( item . url ) ) ;
118175 } }
119176 class :focused = { use ( this . focusindex ) . map (
120177 ( i ) => i - 1 === this . overflowItems . indexOf ( item )
121178 ) }
122179 >
123- < IconButton icon = { iconSearch } > </ IconButton >
124- < span > { item } </ span >
180+ < img
181+ class = "favicon"
182+ src = { item . favicon || "/vite.svg" }
183+ alt = "favicon"
184+ />
185+ { ( item . title && < span class = "description" > { item . title } - </ span > ) ||
186+ "" }
187+ < span class = "url" > { item . url } </ span >
125188 </ div >
126189 ) ) }
127190 </ div >
@@ -149,8 +212,10 @@ export const UrlInput: Component<
149212 if ( e . key === "Enter" ) {
150213 e . preventDefault ( ) ;
151214 if ( this . focusindex > 0 ) {
152- this . value = this . overflowItems [ this . focusindex - 1 ] ;
153- this . navigate ( this . value ) ;
215+ // this.value = this.overflowItems[this.focusindex - 1].;
216+ browser . activetab . pushNavigate (
217+ new URL ( this . overflowItems [ this . focusindex - 1 ] . url )
218+ ) ;
154219 this . active = false ;
155220 this . input . blur ( ) ;
156221 } else {
@@ -167,15 +232,7 @@ export const UrlInput: Component<
167232 { use ( this . active )
168233 . map ( ( a ) => ! a )
169234 . andThen (
170- < span class = "inactiveurl" >
171- { use ( this . tabUrl ) . map (
172- ( v ) =>
173- ( v . protocol === "puter:" ? v . protocol : "" ) +
174- v . host +
175- v . pathname +
176- v . search
177- ) }
178- </ span >
235+ < span class = "inactiveurl" > { use ( this . tabUrl ) . map ( trimUrl ) } </ span >
179236 ) }
180237
181238 < IconButton icon = { iconStar } > </ IconButton >
@@ -190,6 +247,12 @@ UrlInput.style = css`
190247 display : flex;
191248 height : 100% ;
192249 }
250+
251+ .favicon {
252+ width : 16px ;
253+ height : 16px ;
254+ }
255+
193256 .overflow {
194257 position : absolute;
195258 display : none;
@@ -207,6 +270,20 @@ UrlInput.style = css`
207270 align-items : center;
208271 height : 2.5em ;
209272 cursor : pointer;
273+ gap : 0.5em ;
274+ padding-left : 0.5em ;
275+ white-space : nowrap;
276+ }
277+ .overflowitem .url ,
278+ .overflowitem .description {
279+ text-overflow : ellipsis;
280+ text-wrap : nowrap;
281+ word-wrap : nowrap;
282+ overflow : hidden;
283+ }
284+
285+ .overflowitem .url {
286+ color : grey;
210287 }
211288 .overflowitem .focused {
212289 background : blue;
0 commit comments