@@ -3,20 +3,32 @@ import { useEffect, useMemo, useRef, useState } from "react";
33import { actionBarClass , addressInputClass , classNames , closeButtonClass , encodeProxyUrl , formatUrl , getActualUrl , getDefaultUrl , iconButtonClass , type Tab , tabButtonClass } from "@/lib/tabs" ;
44
55export default function Browser ( ) {
6- const [ tabs , setTabs ] = useState < Tab [ ] > ( [ { id : 1 , title : "New Tab" , url : "about:blank" , active : true , reloadKey : 0 } ] ) ;
6+ const [ tabs , setTabs ] = useState < Tab [ ] > ( [ { id : 1 , title : "Tab 1 " , url : "about:blank" , active : true , reloadKey : 0 } ] ) ;
77 const [ url , setUrl ] = useState ( "about:blank" ) ;
8+ const [ favicons , setFavicons ] = useState < { [ key : number ] : string } > ( { } ) ;
89 const activeTab = useMemo ( ( ) => tabs . find ( ( tab ) => tab . active ) , [ tabs ] ) ;
910 const iframeRefs = useRef < { [ key : number ] : HTMLIFrameElement | null } > ( { } ) ;
1011
1112 useEffect ( ( ) => {
12- const defaultUrl = getDefaultUrl ( ) ;
13- setTabs ( ( prev ) => prev . map ( ( tab ) => ( { ...tab , url : defaultUrl } ) ) ) ;
14- setUrl ( defaultUrl ) ;
13+ let firstTabUrl = getDefaultUrl ( ) ;
14+ try {
15+ const goUrl = sessionStorage . getItem ( "goUrl" ) ;
16+ if ( goUrl && goUrl . trim ( ) ) {
17+ firstTabUrl = goUrl ;
18+ }
19+ } catch ( error ) {
20+ console . warn ( "Session storage access failed:" , error ) ;
21+ }
22+
23+ setTabs ( ( prev ) => prev . map ( ( tab ) => ( { ...tab , url : firstTabUrl } ) ) ) ;
24+ setUrl ( firstTabUrl ) ;
1525 } , [ ] ) ;
1626
1727 useEffect ( ( ) => {
1828 if ( activeTab ) {
19- setUrl ( activeTab . url ) ;
29+ const iframe = iframeRefs . current [ activeTab . id ] ;
30+ const actualUrl = getActualUrl ( iframe ) ;
31+ setUrl ( actualUrl || activeTab . url ) ;
2032 }
2133 } , [ activeTab ] ) ;
2234
@@ -30,13 +42,33 @@ export default function Browser() {
3042 const actualUrl = getActualUrl ( iframe ) ;
3143 if ( actualUrl && actualUrl !== url ) {
3244 setUrl ( actualUrl ) ;
45+ }
3346
34- try {
35- const hostname = new URL ( actualUrl ) . hostname ;
36- setTabs ( ( prev ) => prev . map ( ( tab ) => ( tab . id === activeTab . id ? { ...tab , title : hostname || "New Tab" } : tab ) ) ) ;
37- } catch ( e ) {
38- // Invalid URL
47+ try {
48+ const iframeTitle = iframe . contentWindow ?. document ?. title ;
49+ if ( iframeTitle && iframeTitle !== activeTab . title ) {
50+ setTabs ( ( prev ) => prev . map ( ( tab ) => ( tab . id === activeTab . id ? { ...tab , title : iframeTitle } : tab ) ) ) ;
3951 }
52+
53+ const iframeDoc = iframe . contentWindow ?. document ;
54+ if ( iframeDoc ) {
55+ const faviconLink =
56+ iframeDoc . querySelector < HTMLLinkElement > ( 'link[rel="icon"]' ) ||
57+ iframeDoc . querySelector < HTMLLinkElement > ( 'link[rel="shortcut icon"]' ) ||
58+ iframeDoc . querySelector < HTMLLinkElement > ( 'link[rel="apple-touch-icon"]' ) ;
59+
60+ if ( faviconLink ?. href ) {
61+ setFavicons ( ( prev ) => ( { ...prev , [ activeTab . id ] : faviconLink . href } ) ) ;
62+ } else if ( actualUrl ) {
63+ try {
64+ const urlObj = new URL ( actualUrl ) ;
65+ const defaultFavicon = `${ urlObj . origin } /favicon.ico` ;
66+ setFavicons ( ( prev ) => ( { ...prev , [ activeTab . id ] : defaultFavicon } ) ) ;
67+ } catch ( e ) {
68+ }
69+ }
70+ }
71+ } catch ( e ) {
4072 }
4173 } ;
4274
@@ -59,14 +91,17 @@ export default function Browser() {
5991 active : tab . id === id ,
6092 } ) ) ,
6193 ) ;
62- setUrl ( target . url ) ;
94+
95+ const iframe = iframeRefs . current [ id ] ;
96+ const actualUrl = getActualUrl ( iframe ) ;
97+ setUrl ( actualUrl || target . url ) ;
6398 } ;
6499
65100 const addNewTab = ( ) => {
66101 setTabs ( ( prev ) => {
67102 const nextId = prev . length ? Math . max ( ...prev . map ( ( tab ) => tab . id ) ) + 1 : 1 ;
68103 const newTabs = prev . map ( ( tab ) => ( { ...tab , active : false } ) ) ;
69- return [ ...newTabs , { id : nextId , title : "New Tab" , url : getDefaultUrl ( ) , active : true , reloadKey : 0 } ] ;
104+ return [ ...newTabs , { id : nextId , title : ` Tab ${ nextId } ` , url : getDefaultUrl ( ) , active : true , reloadKey : 0 } ] ;
70105 } ) ;
71106 setUrl ( getDefaultUrl ( ) ) ;
72107 } ;
@@ -77,8 +112,16 @@ export default function Browser() {
77112 const filtered = prev . filter ( ( tab ) => tab . id !== id ) ;
78113
79114 if ( filtered . length === 0 ) {
80- const defaultUrl = getDefaultUrl ( ) ;
81- return [ { id : Date . now ( ) , title : "New Tab" , url : defaultUrl , active : true , reloadKey : 0 } ] ;
115+ let firstTabUrl = getDefaultUrl ( ) ;
116+ try {
117+ const goUrl = sessionStorage . getItem ( "goUrl" ) ;
118+ if ( goUrl && goUrl . trim ( ) ) {
119+ firstTabUrl = goUrl ;
120+ }
121+ } catch ( error ) {
122+ console . warn ( "Session storage access failed:" , error ) ;
123+ }
124+ return [ { id : Date . now ( ) , title : "Tab 1" , url : firstTabUrl , active : true , reloadKey : 0 } ] ;
82125 } else if ( ! filtered . some ( ( tab ) => tab . active ) ) {
83126 filtered [ 0 ] = { ...filtered [ 0 ] , active : true } ;
84127 nextUrl = filtered [ 0 ] . url ;
@@ -104,7 +147,6 @@ export default function Browser() {
104147 ? {
105148 ...tab ,
106149 url : formattedUrl ,
107- title : new URL ( formattedUrl ) . hostname || "New Tab" ,
108150 reloadKey : tab . reloadKey + 1 ,
109151 }
110152 : tab ,
@@ -184,7 +226,13 @@ export default function Browser() {
184226 className = { classNames ( tabButtonClass , tab . active ? "bg-background-secondary text-text shadow-sm" : "bg-background text-text-secondary hover:bg-interactive" ) }
185227 >
186228 < div className = "flex min-w-0 flex-1 items-center gap-2" >
187- < div className = "h-4 w-4 shrink-0 rounded bg-accent/30" />
229+ { favicons [ tab . id ] ? (
230+ < img src = { favicons [ tab . id ] } alt = "" className = "h-4 w-4 shrink-0 rounded" onError = { ( e ) => {
231+ e . currentTarget . style . display = 'none' ;
232+ e . currentTarget . nextElementSibling ?. classList . remove ( 'hidden' ) ;
233+ } } />
234+ ) : null }
235+ < div className = { classNames ( "h-4 w-4 shrink-0 rounded bg-accent/30" , favicons [ tab . id ] ? "hidden" : "" ) } />
188236 < span className = "truncate text-sm" > { tab . title } </ span >
189237 </ div >
190238 < button
@@ -270,4 +318,4 @@ export default function Browser() {
270318 </ div >
271319 </ div >
272320 ) ;
273- }
321+ }
0 commit comments