1
mirror of https://github.com/jakejarvis/hoot.git synced 2025-10-18 20:14:25 -04:00

Integrate country flag icons for improved UI

This commit is contained in:
2025-10-13 11:44:19 -04:00
parent 74ba13f753
commit 19f7cdf2e6
6 changed files with 66 additions and 40 deletions

View File

@@ -8,6 +8,9 @@ import { toRegistrableDomain } from "@/lib/domain-server";
import { getQueryClient } from "@/trpc/query-client";
import { trpc } from "@/trpc/server";
import "country-flag-icons/3x2/flags.css";
import "mapbox-gl/dist/mapbox-gl.css";
export const experimental_ppr = true;
export async function generateMetadata({

View File

@@ -3,7 +3,6 @@
import { memo } from "react";
import MapboxMap, { Marker, NavigationControl } from "react-map-gl/mapbox";
import type { Hosting } from "@/lib/schemas";
import "mapbox-gl/dist/mapbox-gl.css";
function MapInner({ hosting }: { hosting: Hosting }) {
if (!process.env.NEXT_PUBLIC_MAPBOX_TOKEN) return null;

View File

@@ -1,5 +1,6 @@
"use client";
import { hasFlag } from "country-flag-icons";
import { MailQuestionMark } from "lucide-react";
import dynamic from "next/dynamic";
import { ErrorWithRetry } from "@/components/domain/error-with-retry";
@@ -16,6 +17,7 @@ import {
} from "@/components/ui/empty";
import type { Hosting } from "@/lib/schemas";
import { SECTION_DEFS } from "@/lib/sections-meta";
import { cn } from "@/lib/utils";
const HostingMap = dynamic(
() => import("@/components/domain/hosting-map").then((m) => m.HostingMap),
@@ -119,7 +121,18 @@ export function HostingEmailSection({
: ""
}`}
leading={
data.geo.emoji ? <span>{data.geo.emoji}</span> : undefined
data.geo.country_code &&
hasFlag(data.geo.country_code.toUpperCase()) ? (
<span
className={cn(
"!w-[15px] !h-[10px] relative top-[2px] inline-block rounded-xs",
// https://gitlab.com/catamphetamine/country-flag-icons/-/tree/master/flags/3x2
`flag:${data.geo.country_code.toUpperCase()}`,
)}
aria-hidden="true"
title={data.geo.country || data.geo.country_code}
/>
) : undefined
}
/>

View File

@@ -39,6 +39,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"country-flag-icons": "^1.5.21",
"date-fns": "^4.1.0",
"geist": "^1.5.1",
"icojs": "^0.19.5",
@@ -67,7 +68,7 @@
"zod": "^4.1.12"
},
"devDependencies": {
"@biomejs/biome": "2.2.5",
"@biomejs/biome": "2.2.6",
"@tailwindcss/postcss": "^4.1.14",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "6.9.1",

82
pnpm-lock.yaml generated
View File

@@ -53,6 +53,9 @@ importers:
cmdk:
specifier: ^1.1.1
version: 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.16))(@types/react@19.1.16)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
country-flag-icons:
specifier: ^1.5.21
version: 1.5.21
date-fns:
specifier: ^4.1.0
version: 4.1.0
@@ -133,8 +136,8 @@ importers:
version: 4.1.12
devDependencies:
'@biomejs/biome':
specifier: 2.2.5
version: 2.2.5
specifier: 2.2.6
version: 2.2.6
'@tailwindcss/postcss':
specifier: ^4.1.14
version: 4.1.14
@@ -306,55 +309,55 @@ packages:
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
'@biomejs/biome@2.2.5':
resolution: {integrity: sha512-zcIi+163Rc3HtyHbEO7CjeHq8DjQRs40HsGbW6vx2WI0tg8mYQOPouhvHSyEnCBAorfYNnKdR64/IxO7xQ5faw==}
'@biomejs/biome@2.2.6':
resolution: {integrity: sha512-yKTCNGhek0rL5OEW1jbLeZX8LHaM8yk7+3JRGv08my+gkpmtb5dDE+54r2ZjZx0ediFEn1pYBOJSmOdDP9xtFw==}
engines: {node: '>=14.21.3'}
hasBin: true
'@biomejs/cli-darwin-arm64@2.2.5':
resolution: {integrity: sha512-MYT+nZ38wEIWVcL5xLyOhYQQ7nlWD0b/4mgATW2c8dvq7R4OQjt/XGXFkXrmtWmQofaIM14L7V8qIz/M+bx5QQ==}
'@biomejs/cli-darwin-arm64@2.2.6':
resolution: {integrity: sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
'@biomejs/cli-darwin-x64@2.2.5':
resolution: {integrity: sha512-FLIEl73fv0R7dI10EnEiZLw+IMz3mWLnF95ASDI0kbx6DDLJjWxE5JxxBfmG+udz1hIDd3fr5wsuP7nwuTRdAg==}
'@biomejs/cli-darwin-x64@2.2.6':
resolution: {integrity: sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
'@biomejs/cli-linux-arm64-musl@2.2.5':
resolution: {integrity: sha512-5Ov2wgAFwqDvQiESnu7b9ufD1faRa+40uwrohgBopeY84El2TnBDoMNXx6iuQdreoFGjwW8vH6k68G21EpNERw==}
'@biomejs/cli-linux-arm64-musl@2.2.6':
resolution: {integrity: sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
'@biomejs/cli-linux-arm64@2.2.5':
resolution: {integrity: sha512-5DjiiDfHqGgR2MS9D+AZ8kOfrzTGqLKywn8hoXpXXlJXIECGQ32t+gt/uiS2XyGBM2XQhR6ztUvbjZWeccFMoQ==}
'@biomejs/cli-linux-arm64@2.2.6':
resolution: {integrity: sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
'@biomejs/cli-linux-x64-musl@2.2.5':
resolution: {integrity: sha512-AVqLCDb/6K7aPNIcxHaTQj01sl1m989CJIQFQEaiQkGr2EQwyOpaATJ473h+nXDUuAcREhccfRpe/tu+0wu0eQ==}
'@biomejs/cli-linux-x64-musl@2.2.6':
resolution: {integrity: sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
'@biomejs/cli-linux-x64@2.2.5':
resolution: {integrity: sha512-fq9meKm1AEXeAWan3uCg6XSP5ObA6F/Ovm89TwaMiy1DNIwdgxPkNwxlXJX8iM6oRbFysYeGnT0OG8diCWb9ew==}
'@biomejs/cli-linux-x64@2.2.6':
resolution: {integrity: sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
'@biomejs/cli-win32-arm64@2.2.5':
resolution: {integrity: sha512-xaOIad4wBambwJa6mdp1FigYSIF9i7PCqRbvBqtIi9y29QtPVQ13sDGtUnsRoe6SjL10auMzQ6YAe+B3RpZXVg==}
'@biomejs/cli-win32-arm64@2.2.6':
resolution: {integrity: sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
'@biomejs/cli-win32-x64@2.2.5':
resolution: {integrity: sha512-F/jhuXCssPFAuciMhHKk00xnCAxJRS/pUzVfXYmOMUp//XW7mO6QeCjsjvnm8L4AO/dG2VOB0O+fJPiJ2uXtIw==}
'@biomejs/cli-win32-x64@2.2.6':
resolution: {integrity: sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
@@ -2313,6 +2316,9 @@ packages:
typescript:
optional: true
country-flag-icons@1.5.21:
resolution: {integrity: sha512-0KmU4oeiyAM+F+atzK99ghQDQJKxEY3tiDhnRraVFL4o65rZgrmrx7xKi0b+hxcVpcEpuUbu+KCC6TKTZQTDcA==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -4108,39 +4114,39 @@ snapshots:
'@bcoe/v8-coverage@1.0.2': {}
'@biomejs/biome@2.2.5':
'@biomejs/biome@2.2.6':
optionalDependencies:
'@biomejs/cli-darwin-arm64': 2.2.5
'@biomejs/cli-darwin-x64': 2.2.5
'@biomejs/cli-linux-arm64': 2.2.5
'@biomejs/cli-linux-arm64-musl': 2.2.5
'@biomejs/cli-linux-x64': 2.2.5
'@biomejs/cli-linux-x64-musl': 2.2.5
'@biomejs/cli-win32-arm64': 2.2.5
'@biomejs/cli-win32-x64': 2.2.5
'@biomejs/cli-darwin-arm64': 2.2.6
'@biomejs/cli-darwin-x64': 2.2.6
'@biomejs/cli-linux-arm64': 2.2.6
'@biomejs/cli-linux-arm64-musl': 2.2.6
'@biomejs/cli-linux-x64': 2.2.6
'@biomejs/cli-linux-x64-musl': 2.2.6
'@biomejs/cli-win32-arm64': 2.2.6
'@biomejs/cli-win32-x64': 2.2.6
'@biomejs/cli-darwin-arm64@2.2.5':
'@biomejs/cli-darwin-arm64@2.2.6':
optional: true
'@biomejs/cli-darwin-x64@2.2.5':
'@biomejs/cli-darwin-x64@2.2.6':
optional: true
'@biomejs/cli-linux-arm64-musl@2.2.5':
'@biomejs/cli-linux-arm64-musl@2.2.6':
optional: true
'@biomejs/cli-linux-arm64@2.2.5':
'@biomejs/cli-linux-arm64@2.2.6':
optional: true
'@biomejs/cli-linux-x64-musl@2.2.5':
'@biomejs/cli-linux-x64-musl@2.2.6':
optional: true
'@biomejs/cli-linux-x64@2.2.5':
'@biomejs/cli-linux-x64@2.2.6':
optional: true
'@biomejs/cli-win32-arm64@2.2.5':
'@biomejs/cli-win32-arm64@2.2.6':
optional: true
'@biomejs/cli-win32-x64@2.2.5':
'@biomejs/cli-win32-x64@2.2.6':
optional: true
'@borewit/text-codec@0.1.1': {}
@@ -5980,6 +5986,8 @@ snapshots:
optionalDependencies:
typescript: 5.9.3
country-flag-icons@1.5.21: {}
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1

View File

@@ -16,6 +16,8 @@ export async function lookupIpMeta(ip: string): Promise<{
const res = await fetch(`https://ipwho.is/${encodeURIComponent(ip)}`);
if (!res.ok) throw new Error("ipwho.is fail");
// https://ipwhois.io/documentation
// https://chatgpt.com/s/t_68ed0de1e01881919c2545fe40ffc7ac
const j = (await res.json()) as {
ip?: string;
success?: boolean;