AI 资讯
Stop Copying shadcn Components Across Projects — Use This Turborepo Starter Instead
You know the drill. You build a beautiful set of shadcn/ui components for Project A — a Button, a Card, a Dialog with custom animations. Then Project B kicks off. You copy the files over. Then Project C. Then a subtle bug is found in the Button. Now you're patching it in three places. This is the classic monorepo problem, and it's exactly what I set out to fix. What I Built turborepo-react-shadcn-starter is a production-ready monorepo template that wires up: Turborepo for workspace orchestration and intelligent build caching React + Vite for the fastest possible frontend dev experience shadcn/ui as a shared package — write once, use everywhere TypeScript across the entire workspace ESLint with shared config baked in The key insight: shadcn/ui lives in @repo/ui , a shared package, not inside any single app. Every app in your monorepo consumes the same components from the same source of truth. The Problem with Typical Setups Most teams drop shadcn/ui directly into a single app. That works fine until you need a second app. Then your choices are: Copy-paste the components → drift and duplication immediately Publish to npm → versioning overhead for internal code Monorepo with a shared package → ✅ This is the right answer Turborepo makes option 3 near-effortless, but setting it up from scratch (workspace configs, TypeScript path aliases, ESLint sharing, shadcn CLI pointing at the right package) takes a few hours of trial and error. This starter eliminates all of that. What's Inside turborepo-react-shadcn-starter/ ├── apps/ │ └── web/ # Vite + React app ├── packages/ │ ├── ui/ # @repo/ui — shared shadcn/ui components │ ├── eslint-config/ # @repo/eslint-config │ └── typescript-config/ # @repo/typescript-config ├── turbo.json └── package.json apps/web — The Main App A clean Vite + React app already wired to consume components from @repo/ui . No boilerplate to delete, no config to untangle. packages/ui — The Shared Component Library This is where all your shadcn/ui components
AI 资讯
Building AI-Native Frontends with Claude Code and MCP
Headline: The wins come from context, not cleverness. An AI with your codebase, your design system, and your deploy logs in scope writes code that ships. Without that scope, it writes plausible code that doesn't. Two years ago, AI coding tools were autocomplete with attitude. In 2026 they are a credible second engineer — provided you build the workflow around them. This is the workflow I run today at Devya Solutions and on personal projects like eng-ahmed.com . The Stack Claude Code in the terminal — long-horizon, multi-file edits with skills and subagents. MCP (Model Context Protocol) servers for live access to docs, deployments, browser, and design tools. Cursor or VS Code for inline edits when I want to stay in the IDE. Why Context Is Everything The single highest-leverage move in AI-assisted dev is feeding the model the right context. MCP servers do this without prompt stuffing. Docs MCP — pulls current library docs at call time, so the model doesn't hallucinate the Tailwind v3 API in a v4 codebase. Browser MCP (Claude-in-Chrome) — lets the agent open the running dev server, screenshot the page, and verify the change actually rendered. Vercel MCP — fetches deploy logs and runtime errors directly. No more pasting logs. Context-mode MCP — keeps file scans, search results, and command output in a sandbox, only surfacing what's relevant to your conversation. A Real Workflow The blog page redesign I just shipped was built in a single 45-minute session. Rough flow: State the goal — two sentences, not a spec doc. Let the agent scout — Claude Code greps, reads a few files, proposes a plan. Iterate visually — screenshot the result, feed it back. The agent fixes the sticky-filter scroll bug in one turn. Commit and push — a single cm shortcut runs build, commits, and pushes. Vercel deploys on push. What the Agent Is Still Bad At Holistic taste — it copies the closest example in your codebase. If that's mediocre, the new feature is mediocre. Domain knowledge — it doesn't kn
AI 资讯
Handling React Dialog Flows with async/await
React dialogs often start simple. You add an isOpen state, then a selected item state, then confirm/cancel callbacks, then another dialog after the first one. Eventually, a simple flow can become scattered across multiple components. For example, a user flow like this: Select a user Confirm the action Add the user often becomes multiple pieces of state: const [ isUserSearchOpen , setIsUserSearchOpen ] = useState ( false ); const [ isConfirmOpen , setIsConfirmOpen ] = useState ( false ); const [ selectedUser , setSelectedUser ] = useState < User | null > ( null ); This works, but the actual flow is harder to read. What if dialogs could be handled as async flows? I wanted the code to read closer to the user flow: const user = await openAsync ( UserSearchDialog ); if ( ! user ) return ; const confirmed = await openAsync ( ConfirmDialog , { title : `Add ${ user . name } ?` , }); if ( confirmed ) { await addUser ( user . id ); } The dialog opens, waits for a result, and the caller continues based on that result. This is about orchestration, not UI This is not meant to replace Radix, MUI, Headless UI, shadcn/ui, or custom dialog components. Those libraries solve the dialog UI problem well. The idea here is to manage the flow around dialogs: opening dialogs from anywhere under a provider resolving typed result values handling nested dialogs distinguishing completed vs dismissed supporting dismissal reasons guarding close behavior with shouldClose So the actual dialog UI can still be your own component. I packaged the pattern I turned this idea into a small open-source library called react-dialog-flow . It provides a headless dialog stack, Promise-based openAsync , typed results, nested dialogs, closeTop , closeAll , dismissal reasons, shouldClose , and optional UI primitives. GitHub: https://github.com/CHOKANGYEOL/react-dialog-flow npm: https://www.npmjs.com/package/react-dialog-flow Docs: https://dialog-flow.kangyeol.com/ It is still early, so I am mainly looking for feed
AI 资讯
React.js ~The best practice for conditional statement~
We tend to write React as functional programming because the functional component is the mainstream. In this era, one of the issues we often encounter is conditional statements. There are a variety of conditional statements, such as if, switch, and ternary operator. We confuse when to use them properly. Assign the result of the conditional statement into a variable This makes it easy to read, test, and modify codebases. The representative case is ternary operator const userName = user ? user . name : ' No user found ' ; Of course, we can write the code another way. const point = 80 ; let result ; if ( point >= 70 ) { result = ' passed ' ; } else { result = ' failed ' ; } console . log ( result ); // passed In this way, we can not ensure the immutability of let , and this section with the conditional branch is written in a procedural style. To solve this issue, we have to wrap this in a function. const judge = ( point : number ) => { if ( point >= 70 ) { return ' passed ' ; } return ' failed ' ; }; In addition to wrapping that statement, I suggest that you use early return to save the else statement. Do not write conditional statements in the return value of tsx (the UI rendering portion) ** When there is only a single conditional statement, or there is no need for any execution in the conditional statement. Let's use the ternary operation simply. import { FC } from ' react ' ; import { useQuery } from ' @tanstack/react-query ' ; import getUser from ' domains/getUser ' ; type Props = { userId : number ; }; const Profile : FC < Props > = ( props ) => { const { userId } = props ; const getSpecificUser = async () => { const specificUser = await getUser ( userId ); return specificUser ; }; const { data : user } = useQuery ([ ' user ' , userId ], getSpecificUser ); const userName = user ? user . name : ' User not found ' ; return < p > User : { userName } < /p> ; }; export default Profile ; const userName = user ? user . name : ' User not found ' ; In this statement, you
AI 资讯
Setting Up a Controlled Component
Prologue A while ago, I decided to develop a fully accessible main navigation component in React and write a series of articles documenting the steps it took to create a non-trivial accessible component. In my last development article , I finally completed the requirements for delivering an uncontrolled navigation component with a horizontal layout; with full keyboard functionality, along with adding the niceties of closing sublists when lists are closed and making sure any open sublist on the top row closes when focus shifts away from it. Rather than write an entirely new component for a mobile version, I'm going to modify the existing code. This first article outlines the steps necessary to set up and work with a controlled component. -— Note : This article is one of a series demonstrating building a React navigational component from scratch while considering accessibility through the process. The articles are accompanied by a GitHub repository with releases tied to one or more articles; each builds on the previous one until a fully implemented navigation component is complete. Each release and its associated tag contain fully runnable code for the article. The code discussed in this article is available in the release. and may be downloaded at release 1.0.0 . Links in the article will take you to the proper file in the tagged GitHub Repository. Because the code for this release is scattered across components, line numbers are added to make it easier to locate in the linked GitHub file. Line numbers are also provided for those who would like to follow along with a downloaded copy. While code examples are written in JavaScript for brevity, all actual code is written in Typescript and targets React 19.x, all while using vanilla CSS. Examples use Next.js v16.x, which is not required to run the navigation component. You can view the requirements for the Controlled Components Release along with previous requirements. Content Links Introduction Acceptance Criteria Contr
AI 资讯
React useIsomorphicLayoutEffect: Fix the SSR useLayoutEffect Warning (2026)
You added a useLayoutEffect to measure a tooltip, shipped it, and the next time your Next.js (or Remix, or Gatsby) dev server rendered a page on the server, the console lit up: Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. The warning is correct, the suggested fix ("only use it on the client") is unhelpful, and the obvious workaround — just switch to useEffect — quietly reintroduces the visual bug you used useLayoutEffect to kill in the first place. useIsomorphicLayoutEffect is the small hook that resolves the standoff. This post explains exactly why the warning happens, why the two naive fixes are both wrong, and what the one-line hook actually does. Why useLayoutEffect Exists At All React gives you two effect hooks that look nearly identical: useEffect runs after the browser has painted. Its callback is queued and fires asynchronously once the frame is on screen. useLayoutEffect runs before the browser paints, synchronously, right after React has mutated the DOM but before the user sees anything. That timing difference is the whole point. If you need to read layout — getBoundingClientRect , scrollHeight , the measured width of a node — and then write a style based on it, you have to do it before paint. Otherwise the user sees one frame of the wrong layout, then a flicker as your useEffect corrects it. The canonical example is a tooltip that has to position itself relative to its own measured size: function Tooltip ({ targetRect , children }) { const ref = useRef < HTMLDivElement > ( null ); const [ pos , setPos ] = useState ({ top : 0 , left : 0 }); useLayoutEffect (() => { const { height , width } = ref . current ! . getBoundingClientRect (); // place the tooltip above the target, centered s
AI 资讯
You don't need NextJS: here's why
This is the public, sanitized version of an internal proposal I wrote to move our production app off Next.js. Next.js is the default answer to "I want to build a React app." It's a great framework. But default and necessary aren't the same word. The gap between them quietly cost us speed, debuggability, and a surprising amount of cross-team friction. We were building an authenticated, data-heavy product: dashboards, filters, charts. Almost every screen lived behind a login and updated in response to clicks. For that shape of app, server-side rendering wasn't buying us much, and it was charging us a lot. First, the only question that matters The right architecture depends on what you're building. Content-first: Marketing sites, blogs, storefronts, docs. Mostly public, SEO matters, lots of static content. SSR/SSG is a genuinely great fit. Use Next.js. Seriously. Application-first: Internal tools, dashboards, admin panels, SaaS consoles. Behind auth, highly interactive, bottlenecked by your API and DB — not by React rendering. Put an application-first product on a content-first framework and you pay for machinery you never use. That was us. What SSR actually cost us Production debugging got harder Server-rendered errors don't map cleanly to the components you wrote, so root-causing took longer every single time. Client-side, the error happens in the browser with a stack trace that points at your component. Boring and fast to fix. Server components fought our tests You can't cleanly unit test a server component that renders other server components. Tools like React Testing Library expect renderable elements, not the serialized output a server component produces. We ended up making design choices purely to stay testable. Tail wagging the dog. Authentication became a distributed-systems problem This was a big one. If you gate protected pages on the server, the server must read and validate the token on every request, then propagate auth state through hydration. That singl
AI 资讯
Building an AI Chat Agent with MCP, Spring AI
Model Context Protocol (MCP) is an open standard for connecting AI apps to tools and data sources. A useful way to think about it is as a USB-C port for AI: one standard interface that lets different models plug into different capabilities without custom glue code for every integration. In this project, we combine MCP, Spring AI, and Google Gemini to build a chat app that can answer weather questions using real tools instead of hallucinating. The system has three parts: MCP tool server - a Spring Boot service that exposes weather and geocoding tools AI chat agent - a Spring Boot service that uses Spring AI + Gemini and calls MCP tools when needed React chat UI - a lightweight frontend for sending messages and rendering replies The result is a small but realistic architecture you can extend into a production assistant. Architecture User (Browser:3000) | POST /api/chat v AI Agent (Spring:7171) -- MCP / Streamable HTTP --> MCP Server (Spring:7170) | | | Google Gemini | Bright Sky API (weather) | | OpenStreetMap Nominatim (geocoding) v v Chat response Tool execution The full source code is available on GitHub . 1. The MCP Tool Server The tool server is a Spring Boot application that exposes MCP tools through Spring AI's annotation scanner. It runs on port 7170 and uses Streamable HTTP for transport. Dependencies <dependency> <groupId> org.springframework.ai </groupId> <artifactId> spring-ai-starter-mcp-server-webmvc </artifactId> </dependency> <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-web </artifactId> </dependency> Defining tools With Spring AI, a tool is just a Spring bean method annotated with @McpTool : @Component public class WeatherTool { private final WeatherToolService weatherToolService ; public WeatherTool ( WeatherToolService weatherToolService ) { this . weatherToolService = weatherToolService ; } @McpTool ( name = "get_current_weather" , description = "Get current weather by dwd_station_id or by lat/lon" ) p
开发者
Article: Beyond CLEAN and MVP: Architecting an Offline-first Reactive Data Layer in Android
With the Reactive Data Layer Architecture (RDLA), you establish a clear boundary between public data APIs and private, framework-specific data-source implementations. Your presentation layer operates in a purely reactive manner, observing data changes rather than procedurally querying them. RDLA also simplifies testing by encouraging you to program to interfaces and use clean seeding patterns. By Mervyn Anthony
AI 资讯
Styling the Vertical - Achieving Parity
Note : This article is one of a series demonstrating building a React navigational component from scratch while considering accessibility through the process. The articles are accompanied by a GitHub repository with releases tied to one or more articles; each builds on the previous one until a fully implemented navigation component is complete. Each release and its associated tag contain fully runnable code for the article. The code discussed in this article is available in the release. and may be downloaded at release 0.9.0 . A page showcasing these base components may be run locally through this release. While code examples are written in JavaScript for brevity, all actual code is written in Typescript and targets React 19.x, all while using vanilla CSS. Examples use Next.js v16.x, which is not required to run the navigation component.] The design requirements for this release are available . -— Content Links Introduction Layout Appearance <nav / > Generic Styling Reimagining Focus and Hover Achieving Parity aria-current Refinements Summary Introduction With only one more release coming up and the horizontal layout styling complete, now is the time to focus on completing vertical layout styling. Most of the layout itself was completed in an earlier release and described in the article Laying it all out on the vertical . When styling a component, care must be taken to ensure parity with the information provided by screen readers through some aria attributes. For instance, a navigation component must set the aria-current="page" attribute on a link whose href points to the current page. In the example being shown, the link in question is the "by Era" link, under Find Your Next Story and Tales. ) While screen reader users hear which button or link is the item currently capturing focus, styling is needed to achieve the same for screen users. Visual styling is necessary to guarantee that visual and auditory/tactile users have the same information. Layout @layer system-c
AI 资讯
I built a developer portfolio template with React, Vite & Tailwind — here's what I learned
As a systems engineering student and frontend dev, I wanted a portfolio that looked professional without spending days fighting with design. So I built one — and ended up turning it into a reusable template. Here's what I focused on while building it: 1. Customization from a single file The biggest pain with most templates is digging through components to change your info. I put everything — name, bio, projects, skills, social links — into ONE config file. Edit that, and the whole site updates. 2. Light & dark mode Developers love dark mode, so I made it the default, with a smooth toggle for light mode. Both are fully themed. 3. Mobile-first & responsive Most people will view a portfolio on their phone, so I built it mobile-first and tested it down to small screens. 4. Easy deployment It works out of the box with Vercel or any static host, with a beginner-friendly setup guide in the README. The stack React + Vite Tailwind CSS Formspree-ready contact form You can see the live demo here: devfolio-template-vercel-app.vercel.app I also made it available as a template if it's useful to anyone: https://payhip.com/b/t1VUk Would love to hear your feedback — what do you look for in a developer portfolio? react #webdev #tailwindcss #showdev
AI 资讯
Forget the Cloud: Building a Privacy-First AI Health Coach with Llama-3 and MLC-LLM on Your iPhone
We live in an era where our most intimate data—heart rates, sleep cycles, and step counts—is constantly uploaded to the cloud for "analysis." But what if you could have a world-class AI medical assistant living entirely on your device? Today, we are pushing the boundaries of Edge AI and Privacy-preserving machine learning by deploying a quantized Llama-3 model directly onto an iPhone using MLC-LLM . By leveraging Apple HealthKit and hardware acceleration via Metal , we can transform "Pixels and Pulses" into actionable insights without a single byte leaving the device. This tutorial dives deep into the architecture of on-device LLMs, specifically focusing on how to bridge the gap between high-performance C++ runtimes and a React Native UI. If you're interested in more advanced patterns for production-grade AI integration, be sure to explore the engineering deep-dives at the WellAlly Blog , which served as a massive inspiration for this architecture. 🚀 The Architecture: Why On-Device? The challenge with running Llama-3 on mobile isn't just memory—it's the data pipeline. We need to fetch sensitive data from HealthKit, format it into a prompt, and run inference using the phone's GPU. System Data Flow graph TD A[User Query: How was my sleep?] --> B[React Native UI] B --> C{Swift Bridge} C --> D[Apple HealthKit API] D --> E[Health Data Context] E --> F[MLC-LLM Engine] G[Quantized Llama-3 Weights] --> F F --> H[On-Device Inference via Metal] H --> I[AI Generated Health Report] I --> B 🛠 Prerequisites MLC-LLM : Our compiler stack for universal LLM deployment. TVM (Tensor Virtual Machine) : The backbone for hardware acceleration. React Native : For the cross-platform UI. Xcode & Swift : To interface with Apple's HealthKit. Llama-3-8B-Instruct (Quantized) : We'll use 4-bit quantization (q4f16_1) to fit within mobile RAM limits. Step 1: Quantizing Llama-3 for Mobile Standard Llama-3 is too heavy for a phone. We use the MLC-LLM CLI to compile the model into a format that the iP
AI 资讯
I got tired of rewriting the same AI boilerplate so I built a library to fix it
Every time I added AI to a React app, I rewrote the same 200+ lines. Streaming loop. Manual message history. Tool call orchestration. Error handling. setIsLoading(false) only if I remembered. After the third project I stopped and asked: why is nobody solving this the way RTK Query solved REST APIs? So I built Strand ( https://github.com/strand-js/strand ). Before const [messages, setMessages] = useState([]) const [isLoading, setIsLoading] = useState(false) async function send(text) { setIsLoading(true) manually stream tokens manually detect tool calls manually loop until done setIsLoading(false) only if you remembered } After const { messages, send, isPending, isStreaming, cancel } = useConversation({ system: 'You are a helpful assistant.', }) Streaming, history, tool calls, cancellation, retry; all handled. The thing nobody else has: useToolCall Works from ANY component; no prop drilling function WeatherStatus() { const { status, input, output } = useToolCall('get_weather') if (status === 'running') return <div>Checking {input?.location}…</div> if (status === 'done') return <div>{output?.temp}°F</div> return null } Live tool state: pending → running → done. Its observable anywhere in your tree. Fixing the isLoading design flaw The Vercel AI SDK has 4+ open issues ( https://github.com/vercel/ai/issues ) about isLoading getting stuck. The reason is architectural because "request sent" and "tokens arriving" are different states. Strand tracks four: const { isPending, isStreaming, isDone, error } = useConversation() // isPending: waiting for first token // isStreaming: tokens arriving // isDone: just completed // error: something failed Works with Anthropic, OpenAI, and Google Gemini npm install @strand-js/core @strand-js/react zod npm install @strand-js/anthropic # or openai, or google Swap providers by changing one server import. Zero frontend changes. v0.1.8, MIT, open source. → https://github.com/strand-js/strand
AI 资讯
React Server Components in 2026: Patterns, Pitfalls, and When to Actually Use Them
React Server Components in 2026: Patterns, Pitfalls, and When to Actually Use Them Most React Server Components problems stem from teams treating them like regular components with a new rendering location. The architecture shift is deeper than that. RSC fundamentally changes where code executes, what data can cross boundaries, and how developers reason about state. Teams that ignore these constraints burn weeks debugging serialization errors and performance regressions. The pattern that production teams overlook is the server/client boundary itself. Understanding where computation happens, what props can serialize, and when to break out of server rendering determines whether RSC improves or destroys your application's performance. Core Concepts: How RSC Actually Works Under the Hood React Server Components execute on the server and send rendered output to the client. No JavaScript bundle ships for these components. The client receives a serialized tree describing what to render, along with holes for client components to fill. The execution model works like this: the server runs your component tree, fetches data directly, and serializes the result. When the payload reaches the browser, React reconstructs the UI without hydrating server component code. Only client components hydrate with their JavaScript bundles. RSC execution flow from server to client This distinction is critical. Server components cannot use hooks like useState or useEffect because they don't exist in the browser. They render once on the server per request. Client components ship JavaScript and can use the full React API. The implication here is that your component tree becomes a mix of server and client code. The boundary between them determines your bundle size, waterfall depth, and debugging complexity. Production-Ready Patterns: Streaming, Suspense, and Data Fetching The correct pattern for data fetching in server components eliminates the request waterfall. Fetch data directly in the component
AI 资讯
React Folder Structures That Scale: A Practical Guide for Modern Frontend Teams
Learn how to organize React projects for scalability, maintainability, and team collaboration. Introduction As React applications grow, one challenge consistently emerges: project organization . A folder structure that works perfectly for a small side project can quickly become a nightmare when multiple developers contribute to a production-scale application. Whether you're a junior React developer preparing for interviews, a mid-level frontend engineer looking to improve code maintainability, or a technical recruiter trying to understand modern React development practices, understanding scalable React folder structures is essential. In this guide, we'll explore the most popular React folder organization strategies, their pros and cons, and the structure many modern engineering teams use to build scalable applications. Why React Folder Structure Matters A well-organized React project provides several benefits: Faster onboarding for new developers Easier code maintenance Better scalability as features grow Reduced code duplication Improved team collaboration Cleaner separation of concerns Many React applications start simple: src/ ├── App.jsx ├── Home.jsx ├── Login.jsx └── Dashboard.jsx This works initially, but as the project grows to dozens or hundreds of components, finding and maintaining files becomes increasingly difficult. Common React Folder Structure Approaches 1. Type-Based Folder Structure One of the earliest and most common approaches is organizing files by their type. src/ ├── components/ ├── pages/ ├── hooks/ ├── services/ ├── utils/ ├── assets/ └── contexts/ Advantages Easy to understand Suitable for small projects Quick setup Disadvantages Components folder can become enormous Related files are spread across multiple directories Harder to maintain in large teams For example, a user profile feature might have files located in: components/UserProfile.jsx hooks/useUser.js services/userService.js pages/ProfilePage.jsx Finding all files related to one feat
AI 资讯
UseState in React (A beginner's guide)
Your password bar goes from "weak" to "strong" when you add characters. Have you ever wondered how React 'remembers' your inputs? 'State' is your answer. A state remembers what input you added. Assume you are typing your name "John", initial state is the blank slate (starting value, like empty input, counter at zero, or an empty whiteboard) in the input bar, whenever you add a new letter, a function named 'setState' is called to change the state from "" (empty input bar) to "J", then again to "Jo", again to "Joh", etc... And following the setState, React automatically re-renders the UI. Think of re-rendering as erasing everything and re-writing the UI with the new state. Initial state was "", then setState updates it from "" to "J". Following that, React automatically erases the first UI and then it will build a new UI with the new state. Why not just use a variable? You might be thinking, "Why don't just use variables and change them whenever you want it?", and you might do that, but the value only changes in your codebase, but the UI will still show the first value. (and that defeated the purpose) What is [state, setState] concept? const [state, setState] = useState('placeholder') is the basic syntax. useState provides an array of ['current-state', 'function to change state']. It is destructured to the two values (state = 'current-state' and setState = 'function to change state'). When you enter an input, the function is called and the 'current-state' will be updated to the 'new-state'. How to use it To use useState follow these two simple steps: Import useState from 'react' import { useState } from 'react'; Declare it (for example to input age): const [age, setAge] = useState(20); where, 'age' is current state. 'setAge' is the function that will create the new state. 20 is the placeholder. Now try it yourself! Open your React project and add a counter using useState. Watch the UI update every time you click.
开发者
How to open Google Maps in turn-by-turn navigation mode from a PWA (Android)
The next attempt was the standard Maps URL: window . open ( `https://maps.google.com/maps?daddr= ${ lat } , ${ lng } ` , ' _blank ' ); This opens Maps, but in the browser — not the app. And it shows the route preview, not turn-by-turn navigation. What worked: Android Intent URLs Android supports a special URL scheme that tells Chrome to launch a native app directly: window . location . href = `intent://navigation/now?ll= ${ lat } , ${ lng } &title=Next+stop#Intent;scheme=google.navigation;package=com.google.android.apps.maps;end` ; Breaking it down: intent:// — tells Chrome this is an Android intent navigation/now?ll=${lat},${lng} — opens Maps in navigation mode, starting immediately #Intent;scheme=google.navigation — the URI scheme to use package=com.google.android.apps.maps — the target app package end — closes the intent syntax This opens the Google Maps app directly and starts turn-by-turn navigation automatically — no extra taps needed. It also works with Android Auto. The full function export function openNavigation ( destination : { lat : number ; lng : number }): void { window . location . href = `intent://navigation/now?ll= ${ destination . lat } , ${ destination . lng } &title=Next+stop#Intent;scheme=google.navigation;package=com.google.android.apps.maps;end` ; } Call it on any user gesture (tap, click) and it works without being blocked by the browser. The app The full PWA is open source if you want to see the context: 🔗 GitHub repo 🌐 Live app Built with React + TypeScript + Vite + Dexie.js + @vis .gl/react-google-maps. If you're building a PWA that needs to hand off to Google Maps navigation on Android, this intent URL is the cleanest solution I found. Hope it saves you the hour I spent figuring it out.
AI 资讯
Migrating Ekehi from Vanilla JS to a TypeScript Stack
Ekehi platform has moved from hand-written HTML/CSS/JS pages to a typed, component-driven React 19 client and a module-based TypeScript Express/Node.js API. 0. Where we started and where we landed Before. A static client built from per-page folders ( landing/ , contributors/ , login/ , signup/ , admin/ ), each shipping its own index.html , a shared styles.css , and vanilla ES module scripts under client/shared/ . The server was an Express API written in plain JavaScript. After. Layer Before After Client Static HTML + CSS + vanilla JS React 19 + Vite 8 + TanStack Router + TypeScript 6 Styling One global styles.css Tailwind CSS 4 with @theme design tokens Data fetch scattered per page TanStack Query over a typed lib/api client Server Express in JavaScript Express + TypeScript, module-per-domain Repo Two loose folders pnpm workspace with shared git hooks Quality gate None ESLint 9, Prettier 3, Husky, commitlint, Vitest The migration ran in two phases on separate branches: **Phase 1 — client rewrite. **Phase 2 — server rewrite. 1. Why this framework? Choice: React 19 , rendered as a client-side SPA through Vite 8 , routed by TanStack Router . TanStack Router was chosen rather than React Router because it gives fully type-safe routes, first-class search-param typing, built-in code-splitting, and file-based route generation that pairs cleanly with Vite. 2. The folder and component structure The client uses a feature-sliced layout: code is grouped by domain, not by technical type. client/src/ ├── components/ │ ├── layout/ navbar.tsx, footer.tsx │ └── ui/ button, input, modal, select, dropdown, ... (design system) ├── config/ env.ts, env-schema.ts, endpoints.ts ├── features/ one folder per domain │ ├── auth/ auth.query.ts, auth.service.ts, auth.types.ts, components/, pages/ │ ├── opportunities/ pages/ │ ├── resources/ pages/ │ ├── submissions/ pages/ │ ├── admin/ pages/ │ └── site/ pages/ (landing, contributors) ├── lib/ │ ├── api/ request.ts, errors.ts, refresh.ts, types.t
AI 资讯
Building SyncCanvas: An AI-Powered Real-Time Collaborative Whiteboard
Modern collaboration needs more than documents and chat messages. Teams need a shared visual space where ideas can be created, organized, and refined together in real time. That's why I built SyncCanvas — an AI-powered collaborative whiteboard that combines real-time multiplayer collaboration, infinite canvas drawing, and AI-assisted brainstorming into one modern workspace. The Problem Most collaboration tools focus on only one aspect of teamwork. Some are great for drawing. Others are excellent for documentation. AI tools often live in separate windows, disconnected from the creative workflow. I wanted a platform where teams could brainstorm visually while AI actively helped generate and organize ideas directly on the canvas. Introducing SyncCanvas SyncCanvas is an infinite multiplayer whiteboard designed for students, developers, teams, and creators. Key features include: Real-time collaboration with live synchronization Infinite canvas with pan and zoom Drawing tools, shapes, text, and sticky notes AI-powered content generation using Gemini Private room sharing Guest mode access PNG export support WiFi Rooms for local collaboration Real-Time Collaboration Collaboration is at the heart of SyncCanvas. Using Yjs and WebSockets, multiple users can work on the same board simultaneously while seeing updates instantly. Users can: View live cursors Track online participants Join private rooms using secure room codes Collaborate anonymously through guest mode This creates a seamless experience similar to working together in the same room. Infinite Canvas Experience The whiteboard is designed to be limitless. Users can: Draw freehand sketches Create rectangles and circles Add text elements Organize ideas with sticky notes Move freely across an infinite workspace Export workspaces as images The canvas is powered by Fabric.js, providing smooth rendering and flexibility for future enhancements. AI-Powered Brainstorming One of the most exciting features is the integration of G
开发者
TSRX: A Framework-Agnostic Alternative to JSX
TSRX is a TypeScript language extension developed by Dominic Gannaway, designed to build declarative user interfaces in a framework-agnostic manner. It compiles single .tsrx files to various runtime targets and supports scoped styles and declarative error handling. TSRX is currently in alpha and is open source under the MIT license. By Daniel Curtis