+
@@ -62,13 +64,12 @@ const InfoRow = ({
href={href}
target="_blank"
rel="noreferrer"
- className="text-sm text-gray-900 dark:text-gray-100 hover:text-blue-600 dark:hover:text-blue-400 truncate transition-colors flex items-center gap-1"
+ className="text-sm font-medium text-gray-900 dark:text-gray-100 hover:text-blue-600 dark:hover:text-blue-400 truncate transition-colors flex items-center gap-1.5"
>
{value}
-
) : (
-
{value}
+
{value}
)}
{canCopy &&
}
@@ -80,14 +81,33 @@ const InfoRow = ({
export default function ServerInfo({ data }: { data: HostInfo }) {
const { network, location, domain, isBrowserResource } = data;
+ // URL generation for flags
+ const getFlagUrl = (code?: string | null) => {
+ if (!code) return '';
+ try {
+ const path = `/${code.toLowerCase()}.webp`;
+ return browser.runtime.getURL(path as any);
+ } catch {
+ return '';
+ }
+ };
+
// Header Component
- const Header = ({ title, subtitle, icon: Icon }: { title: string, subtitle?: string, icon?: any }) => (
-
- {Icon &&
}
-
-
{title}
- {subtitle &&
{subtitle}
}
+ const Header = ({ title, flagCode }: { title: string, flagCode?: string | null }) => (
+
+
+
+ {title}
+
+ {flagCode && (
+
})
(e.currentTarget.style.display = 'none')}
+ />
+ )}
);
@@ -97,46 +117,55 @@ export default function ServerInfo({ data }: { data: HostInfo }) {
-
-
-
-
-
No network information available for this page.
+
+
+
+
+
+ This page is generated locally by your browser.
);
}
- if (!network) return null;
-
- const flagUrl = location?.countryCode
- ? `/${location.countryCode.toLowerCase()}.webp`
- : '';
+ // Fallback if network data is missing
+ if (!network) {
+ return
;
+ }
// Local Network View
if (network.isLocal) {
return (
@@ -146,64 +175,50 @@ export default function ServerInfo({ data }: { data: HostInfo }) {
// Public Internet View
return (
-
-
-
- {domain}
-
-
-
- Publicly Accessible
-
-
- {location?.countryCode && (
-

(e.currentTarget.style.display = 'none')}
- />
- )}
-
+
-
+
-
-
-
-
+
diff --git a/entrypoints/background.ts b/entrypoints/background.ts
index 03ac38b..1058f4f 100644
--- a/entrypoints/background.ts
+++ b/entrypoints/background.ts
@@ -4,7 +4,7 @@ import { StorageService } from '@/utils/storage';
export default defineBackground({
main() {
- // Listen for Network Responses (Source of Truth for IPs)
+ // Listen for Network Responses
browser.webRequest.onResponseStarted.addListener(
async (details) => {
if (details.tabId === -1 || details.type !== 'main_frame' || !details.ip) return;
@@ -27,7 +27,7 @@ export default defineBackground({
}
});
- // 3. Cleanup
+ // Cleanup
browser.tabs.onRemoved.addListener(async (tabId) => {
await StorageService.remove(tabId);
});
diff --git a/services/icon.ts b/services/icon.ts
index 960a769..8fc8319 100644
--- a/services/icon.ts
+++ b/services/icon.ts
@@ -5,15 +5,9 @@ const ICON_CACHE = new Map
>();
export const IconService = {
async update(tabId: number, countryCode: string | null, isLocal: boolean) {
try {
- if (isLocal) {
- const path = '/icon/128.png' as string;
- await browser.action.setIcon({ tabId, path });
- return;
- }
+ const code = isLocal ? 'unknown' : (countryCode ? countryCode.toLowerCase() : 'unknown');
- const code = countryCode ? countryCode.toLowerCase() : 'unknown';
const imageData = await this.getIconData(code);
-
await browser.action.setIcon({ tabId, imageData });
} catch (e) {
console.warn('Failed to update icon', e);
@@ -37,7 +31,6 @@ export const IconService = {
ICON_CACHE.set(code, data);
return data;
} catch {
- // Fallback to unknown if specific flag fails
if (code !== 'unknown') return this.getIconData('unknown');
throw new Error('Failed to load fallback icon');
}
@@ -52,6 +45,7 @@ export const IconService = {
const offsetX = (canvas.width - bitmap.width * ratio) / 2;
const offsetY = (canvas.height - bitmap.height * ratio) / 2;
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, offsetX, offsetY, bitmap.width * ratio, bitmap.height * ratio);
const sizes = [16, 32, 48, 128];
diff --git a/services/tab.ts b/services/tab.ts
index f6c2588..8ca504e 100644
--- a/services/tab.ts
+++ b/services/tab.ts
@@ -32,7 +32,7 @@ export const Tab = {
return;
}
- // Handle Local/Private IPs
+ // Handle Local/Private IPs (Bogons)
if (IpUtils.isLocalOrBogon(ip)) {
const localInfo: HostInfo = {
...initialState,
@@ -55,8 +55,30 @@ export const Tab = {
// Fetch Public Data
const geoData = await GeoService.resolve(ip);
+ // If Geo lookup fails (e.g. LAN domain with public IP, or API down),
+ // we still want to show the IP we captured.
if (!geoData) {
- await StorageService.set(tabId, { ...initialState, loading: false, error: 'Failed to fetch host info' });
+ const fallbackInfo: HostInfo = {
+ ...initialState,
+ loading: false,
+ network: {
+ ip,
+ hostname: null,
+ asn: null,
+ org: 'Unknown',
+ isLocal: false,
+ isBogon: false
+ },
+ location: {
+ countryCode: null,
+ countryName: 'Unknown Location',
+ city: null,
+ region: null,
+ timezone: null
+ }
+ };
+ await StorageService.set(tabId, fallbackInfo);
+ await IconService.update(tabId, 'unknown', false);
return;
}