惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
人人都是产品经理
人人都是产品经理
月光博客
月光博客
V
V2EX
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
Hugging Face - Blog
Hugging Face - Blog
V
Visual Studio Blog
宝玉的分享
宝玉的分享
雷峰网
雷峰网
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - Franky
博客园 - 聂微东
博客园 - 司徒正美
博客园 - 【当耐特】
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Building a Travel Power Adapter Tool with Claude in a Wee...
Vientapps · 2026-05-04 · via DEV Community

I travel a lot. And every single time, I'm standing in an airport Googling "do I need an adapter for Thailand" while my boarding group is already lining up. The existing tools for this are bad. They're buried in blog posts from 2016 with popup ads, or they're a wall of text that doesn't actually answer the question.

I already had most of the data. My destination guides on Vientapps cover dozens of countries, and each one tracks the local plug type and voltage. The pieces were sitting there. I just needed to turn them into something interactive.

What it does

You pick where you're from and where you're going. It tells you: do you need an adapter, do you need a voltage converter, or do you need nothing. It covers 221 countries, all 15 plug types (A through O), and links you to the right adapter on Amazon if you need one.

There's a collapsible section with plug diagrams, a voltage comparison, and a converter guide. A table of popular routes (US to UK, US to France, etc.) with pre-computed answers. FAQs for the common questions. And the whole thing also works as an embeddable widget other travel sites can iframe in.

How I worked with Claude on this one

This was almost entirely Claude Code agentic runs. I described what I wanted, pointed it at my existing destination data, and let it build. My role was more like a product manager reviewing output than a developer writing code. I'd describe the feature, Claude would ship a complete implementation, I'd review it, and then tell it what to fix.

The initial build took one agentic run. The restyle took another. The whole thing was done in two sessions over two days.

The stack

Astro static page with all logic running client-side in a single <script> block. No framework, no React, no build step beyond what Astro already does. The country data and plug type info get serialized into JSON script tags at build time, then the client-side JS reads them and renders results.

I considered making this a separate app like PackSmart, but it didn't need a backend. Every possible result is just a comparison between two objects in a JSON array. No API calls, no server, no loading states.

export function getAdapterVerdict(origin: CountryElectrical, destination: CountryElectrical): AdapterVerdict {
  const originPlugs = new Set(origin.plugTypes);
  const shared = destination.plugTypes.filter((p) => originPlugs.has(p));
  const missing = destination.plugTypes.filter((p) => !originPlugs.has(p));
  const needsAdapter = shared.length === 0;
  const voltageMatch = Math.abs(origin.voltage - destination.voltage) <= 20;
  const needsConverter = !voltageMatch;

  const freqOrigin = Array.isArray(origin.frequency) ? origin.frequency : [origin.frequency];
  const freqDest = Array.isArray(destination.frequency) ? destination.frequency : [destination.frequency];
  const frequencyMatch = freqOrigin.some((f) => freqDest.includes(f));

  return { needsAdapter, needsConverter, sharedPlugTypes: shared, missingPlugTypes: missing, voltageMatch, frequencyMatch };
}

Enter fullscreen mode Exit fullscreen mode

That's the core logic. If none of your home country's plug types exist in the destination's list, you need an adapter. If the voltage difference is more than 20V, you need a converter. Simple, but it handles the edge cases: countries with multiple plug types, dual-voltage regions, frequency mismatches.

The hard part

Information hierarchy. The tool needs to answer one question fast: "do I need to buy something before my trip?" But it also needs to handle the follow-up questions: "what type?" and "what about my hair dryer?"

Claude's first implementation threw everything at the user at once. Plug diagrams, voltage charts, converter guides, notes about regional voltage variations. It was technically complete and practically unusable. Nobody landing on this page from Google wants to parse a wall of technical data. They want a yes/no verdict with a link to buy the thing.

The fix was progressive disclosure. The verdict sits at the top in a bold banner. The Amazon link is right below it. Everything else collapses behind a details element:

<details id="pf-details" class="pf-details mt-3">
  <summary class="pf-details-summary">
    <span>Voltage details, plug picture, and converter guide</span>
  </summary>
  <div class="pf-details-body">
    <!-- Plug type cards, voltage comparison, converter advice -->
  </div>
</details>

Enter fullscreen mode Exit fullscreen mode

Simple pattern, but it took two full restyle passes to get there because Claude kept defaulting to "show everything."

Where Claude surprised me

The data layer. Claude compiled a 221-country JSON dataset with plug types, voltages, frequencies, and edge-case notes in a single pass. Countries like Brazil where voltage varies by region, Cambodia where five different plug types are in use, Bangladesh where Type D and G are most common despite officially supporting five types.

{"name": "Brazil", "iso": "BR", "plugTypes": ["C", "N"], "voltage": 127, "frequency": 60, "notes": "Voltage varies by region: 127V in most of the southeast (Sao Paulo, Rio) and 220V in the south (Brasilia, Florianopolis) and northeast (Recife, Salvador). Always check before plugging in."}

Enter fullscreen mode Exit fullscreen mode

I spot-checked a bunch of these against IEC standards and travel forums. They were accurate. Claude also generated all 15 plug type SVGs inline, each with the correct pin layout, grounding, and shape. No external image files needed. That saved me from sourcing or licensing illustrations.

Where Claude fell short

The initial UI was a disaster. Claude built something that was technically functional but impossible to actually use. The country selectors were basic dropdowns with no search. The results showed every data point at once with no hierarchy. There was no visual distinction between "you need nothing" and "you need a specific adapter."

I had to run a complete restyle. The first attempt at the restyle was still too busy. I ended up having to be very specific about what I wanted: a horizontal picker row with flag emojis, a single bold verdict line, a dark CTA button, and everything else hidden behind a collapsible. Claude needed that level of direction to produce something clean.

The country picker alone went through multiple iterations:

function initPicker(root: HTMLElement, onSelect: (iso: string, name: string) => void) {
  const trigger = root.querySelector('.pf-picker-trigger') as HTMLButtonElement;
  const panel = root.querySelector('.pf-picker-panel') as HTMLElement;
  const search = root.querySelector('.pf-picker-search') as HTMLInputElement;
  // ...keyboard nav, filtering, popular chips, scroll-into-view
  return { setTriggerDisplay, selectIso };
}

Enter fullscreen mode Exit fullscreen mode

This picker has search, keyboard navigation, popular country chips, and proper ARIA. None of that existed in the first version. Claude could build each individual piece when asked, but it couldn't intuit what the right UX shape was from a high-level description.

What went wrong overall

Scope was actually fine here. The real problem was making two things at once: a standalone tool page and an embeddable widget. The widget version needs to work in an iframe at arbitrary widths, with theme detection, without any of the page chrome. That doubled the surface area for styling bugs.

I also launched it hidden behind a sitemap exclusion initially, which means I didn't get real feedback on the UX until I enabled it on the tools page. If I'd shown it to someone earlier, I might have caught the information-overload problem faster.

Where it is now

Live at /tools/plug-finder. Indexed, included in the tools listing, has an embeddable widget version for outreach. The affiliate links are working. It handles URL parameters (?from=US&to=GB) so you can deep-link to specific routes.

What I would do differently

Start with a wireframe. Not a pixel-perfect mockup, just a rough sketch of the information hierarchy: what does the user see first, what's hidden, what's the action. Claude is great at building whatever you describe, but it defaults to "show all the data" when you don't constrain the layout upfront. A 30-second sketch on paper would have saved me the entire restyle pass.

I'd also be more explicit about the "nothing needed" state. That's actually the most satisfying result for the user, and it deserves its own distinct treatment. Claude's first version treated it as just another line of text. Now it gets a big "Nothing." headline. Small thing, but it's the difference between a tool that feels good to use and one that just dumps information.