<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: dev.family</title>
    <description>The latest articles on DEV Community by dev.family (@dev_family).</description>
    <link>https://dev.to/dev_family</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3632%2F91e92809-8f78-45df-9f89-49b61d0ed98d.png</url>
      <title>DEV Community: dev.family</title>
      <link>https://dev.to/dev_family</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dev_family"/>
    <language>en</language>
    <item>
      <title>Building a Custom E-commerce Analytics Dashboard in Hours with Admiral</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Tue, 13 Jan 2026 11:48:32 +0000</pubDate>
      <link>https://dev.to/dev_family/building-a-custom-e-commerce-analytics-dashboard-in-hours-with-admiral-5hco</link>
      <guid>https://dev.to/dev_family/building-a-custom-e-commerce-analytics-dashboard-in-hours-with-admiral-5hco</guid>
      <description>&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;Recently, we needed to add seller analytics to our e-commerce project. You know the drill: key metrics, charts, data exports, order funnels — the usual set of features that clients expect in their admin panels.&lt;/p&gt;

&lt;p&gt;Typically, building a custom analytics dashboard from scratch takes weeks. But we managed to put it together in just a couple of hours using Admiral, our open-source framework for admin panels.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Admiral?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/dev-family/admiral" rel="noopener noreferrer"&gt;Admiral&lt;/a&gt; is an open-source framework for rapidly building admin panels that works with any backend. Most people use it for quick CRUD operations, but it's capable of much more.&lt;/p&gt;

&lt;p&gt;The key advantage: you're not locked into a specific stack or architecture. Admiral adapts to your backend, not the other way around.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Built
&lt;/h2&gt;

&lt;p&gt;Here's what we assembled for our seller analytics dashboard:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📈 Key Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Revenue tracking&lt;/li&gt;
&lt;li&gt;Order count&lt;/li&gt;
&lt;li&gt;Average order value&lt;/li&gt;
&lt;li&gt;Repeat sales&lt;/li&gt;
&lt;li&gt;Week-over-week trends with historical data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🔄 Business Process Visualization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order funnel by status&lt;/li&gt;
&lt;li&gt;Aggregated counts and totals&lt;/li&gt;
&lt;li&gt;Visual representation of the sales pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🛍️ Sales by Category&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Breakdown of all orders by product categories&lt;/li&gt;
&lt;li&gt;Visual charts for quick insights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;↩️ Returns &amp;amp; Cancellations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dedicated analytics block&lt;/li&gt;
&lt;li&gt;Counts and monetary amounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🎟️ Promo Code Analytics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usage statistics&lt;/li&gt;
&lt;li&gt;Application counts&lt;/li&gt;
&lt;li&gt;Total discount amounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📊 Data Export&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-click export to XLSX and CSV for every block&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Secret Sauce: Cursor Rules
&lt;/h2&gt;

&lt;p&gt;What made this fast? We've developed cursor rules specifically for Admiral that speed up the development of custom interfaces dramatically.&lt;/p&gt;

&lt;p&gt;With these rules, building beautiful and functional dashboards isn't just quick — it's actually enjoyable. The rules handle the boilerplate, letting you focus on the business logic specific to your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;This isn't an out-of-the-box feature that comes with Admiral. This is a &lt;strong&gt;custom dashboard&lt;/strong&gt; we built for specific project needs in a couple of hours.&lt;/p&gt;

&lt;p&gt;That's the point: Admiral gives you the flexibility to build arbitrary interfaces quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom dashboards&lt;/li&gt;
&lt;li&gt;Complex data visualizations&lt;/li&gt;
&lt;li&gt;Tailored analytics&lt;/li&gt;
&lt;li&gt;Whatever your project actually needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No fighting with pre-built components that almost fit your use case. No compromising on features because extending the framework is too painful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Admiral is open source and works with any backend. Whether you need simple CRUDs or complex custom interfaces, it adapts to your needs.&lt;/p&gt;

&lt;p&gt;Check it out: &lt;a href="https://github.com/dev-family/admiral" rel="noopener noreferrer"&gt;https://github.com/dev-family/admiral&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What kind of admin interfaces are you building? Have you found a framework that gives you the right balance of speed and flexibility?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>UX/UI in 2026: Why Beautiful Design No Longer Guarantees Success</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Wed, 17 Dec 2025 12:10:36 +0000</pubDate>
      <link>https://dev.to/dev_family/uxui-in-2026-why-beautiful-design-no-longer-guarantees-success-1ca2</link>
      <guid>https://dev.to/dev_family/uxui-in-2026-why-beautiful-design-no-longer-guarantees-success-1ca2</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.family/blog/article/uxui-ai-and-trends-that-actually-work-in-2026" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; AI commoditized "pixel-perfect" design. In 2026, designers compete on strategy and metrics, not aesthetics. Here's what actually works now.&lt;/p&gt;




&lt;p&gt;Hi Dev.to! 👋&lt;/p&gt;

&lt;p&gt;I'm a product designer who just spent 3 weeks deep-diving into what's actually working in UX/UI 2026. Not what looks pretty on Dribbble, but what moves business metrics and helps developers ship better products.&lt;/p&gt;

&lt;p&gt;The main thesis? &lt;strong&gt;Design is becoming infrastructure, not decoration.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🤖 The AI Shift: What Changed for Designers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The reality:&lt;/strong&gt;&lt;br&gt;
Tools like Figma AI, Galileo AI, and Magician now generate clean layouts in seconds. I can literally type "dashboard for restaurant management app" and get 5 professional-looking variants instantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this means:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Pixel-perfect" is no longer a competitive advantage&lt;/li&gt;
&lt;li&gt;Visual styling is commoditized&lt;/li&gt;
&lt;li&gt;Designers must compete on strategy, not aesthetics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The new value:&lt;/strong&gt;&lt;br&gt;
Understanding user behavior, metrics, and business logic. AI handles the pixels; humans handle the "why."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Old designer value proposition&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;designer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;making things beautiful&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pretty screens&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// New designer value proposition&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;designer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;understanding behavior + metrics&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;interfaces that move numbers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📊 Outcome-Driven UX: Every Screen Needs a Metric
&lt;/h2&gt;

&lt;p&gt;In 2026, every screen you build must answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What behavior are we changing?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Which metric are we moving?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How quickly will we see results?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mandatory metrics:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Activation&lt;/strong&gt;&lt;br&gt;
→ Time to first value&lt;br&gt;
→ How fast does user "get it"?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retention&lt;/strong&gt;&lt;br&gt;
→ Day 1, Day 7, Day 30&lt;br&gt;
→ Do they come back?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conversion&lt;/strong&gt;&lt;br&gt;
→ Free → Paid, Browse → Buy&lt;br&gt;
→ Actual revenue impact&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NPS&lt;/strong&gt;&lt;br&gt;
→ Would they recommend?&lt;br&gt;
→ Real satisfaction metric&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LTV&lt;/strong&gt;&lt;br&gt;
→ Long-term user value&lt;br&gt;
→ Are we building sustainable business?&lt;/p&gt;
&lt;h3&gt;
  
  
  Real example from our work:
&lt;/h3&gt;

&lt;p&gt;We redesigned an onboarding flow for a SaaS product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE:
- 7 steps to first value
- 35% completion rate
- Day 7 retention: 18%

AFTER (outcome-driven approach):
- 3 steps to first value  
- 67% completion rate
- Day 7 retention: 34%

The design wasn't "prettier" - it was more strategic.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🌍 Regional UX Models Going Global
&lt;/h2&gt;

&lt;p&gt;One-size-fits-all UX is dead. Products now adapt interfaces based on regional patterns:&lt;/p&gt;

&lt;h3&gt;
  
  
  Asia (Grab, Gojek, WeChat)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;density&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;high&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;whitespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;minimal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;features-per-screen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;many&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"super-app"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Users expect everything immediately accessible. Dense = efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  India (Zomato, Paytm)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;trust-signals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prominent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;explanations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;detailed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hyper-localized&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"trust-first"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Users approach new products cautiously. Design must explain and build trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  US/Europe (Notion, Linear, Apple)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;whitespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;generous&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;visual-noise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;minimal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"minimalist"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Users value clarity and breathing room. Less = more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The key insight:&lt;/strong&gt; Modern products detect user location/context and adapt UI accordingly. Same backend, different front-end patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  🥽 New Platforms = New UX Patterns
&lt;/h2&gt;

&lt;p&gt;As developers, you're probably already building for these:&lt;/p&gt;

&lt;h3&gt;
  
  
  AR/VR (Apple Vision Pro, Meta Quest)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Traditional UI thinking&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clickable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tap/click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Spatial UI thinking&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spatial-object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gaze + pinch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;floating-at-50cm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;physics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gravity-affected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wearables (Apple Watch, smart glasses)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Screen-based thinking&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;full-screen modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button tap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Wearable thinking&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;glanceable-card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto-after-3s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quick-action-only&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key differences:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gesture-first flows&lt;/strong&gt; (not tap/click)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eye-control navigation&lt;/strong&gt; (gaze as input)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-UI&lt;/strong&gt; (ambient, contextual interfaces)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spatial design&lt;/strong&gt; (3D, depth, physical space)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎨 Visual Trends That Actually Work
&lt;/h2&gt;

&lt;p&gt;Not just "looks cool" - these drive behavior:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Motion-First Design
&lt;/h3&gt;

&lt;p&gt;Animations aren't decoration - they're explanation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Bad: Decoration */&lt;/span&gt;
&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Good: Behavioral signal */&lt;/span&gt;
&lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-2px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c"&gt;/* Communicates: "I'm clickable and will respond" */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.loading-state&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pulse&lt;/span&gt; &lt;span class="m"&gt;1.5s&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c"&gt;/* Communicates: "I'm working, wait for me" */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Warm Minimalism
&lt;/h3&gt;

&lt;p&gt;Less noise, more breathing room, warmer palettes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Old minimalism: cold */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0066FF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Warm minimalism: human */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FAFAF9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1A1A1A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FF6B35&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--surface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#F5F5F4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Liquid Glass + Depth
&lt;/h3&gt;

&lt;p&gt;Borrowed from visionOS, now everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.glass-panel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;inset&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Accessibility as Base Layer
&lt;/h3&gt;

&lt;p&gt;Not optional anymore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Automated checks in CI/CD&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accessibilityChecks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;colorContrast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;=4.5:1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// WCAG AA minimum&lt;/span&gt;
  &lt;span class="na"&gt;focusVisible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;keyboardNav&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;screenReaderLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all-interactive-elements&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;motionPreference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;respect-prefers-reduced-motion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🛠️ Practical Implementation for Developers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Integrate UX Metrics in Your Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Track UX metrics like features&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trackUXMetric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ux_metric&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;metric_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 'activation' | 'retention' | 'conversion'&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getCurrentComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example: Track time to first value&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onboardingStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// ... user completes onboarding ...&lt;/span&gt;
&lt;span class="nf"&gt;trackUXMetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;activation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;time_to_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;onboardingStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Build Adaptive Interfaces
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Detect and adapt to regional patterns&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUXDensity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userLocale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;densityMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asia&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// More content per screen&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;india&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// Balanced with trust signals  &lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// Generous whitespace&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getRegion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userLocale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;densityMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Apply density to layout&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;low&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;24px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nf"&gt;getUXDensity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userLocale&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Respect Familiar Patterns
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Don't reinvent the wheel&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bottom-tab-bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Familiar to everyone&lt;/span&gt;
  &lt;span class="na"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sidebar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;// Expected pattern&lt;/span&gt;
  &lt;span class="c1"&gt;// NOT: 'gesture-only-hidden-menu' (users will struggle)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Innovation through details, not structure&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enhancedNavigation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transitions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;smooth-60fps&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;haptic-on-tap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;persisted-across-sessions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📈 Companies Doing This Right
&lt;/h2&gt;

&lt;p&gt;Real examples to learn from:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notion&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Familiar patterns (blocks, pages, database views)&lt;/li&gt;
&lt;li&gt;Wins on details (smooth animations, smart defaults)&lt;/li&gt;
&lt;li&gt;Every feature tied to engagement metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Linear&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Super predictable structure&lt;/li&gt;
&lt;li&gt;Fast keyboard shortcuts (developer-focused)&lt;/li&gt;
&lt;li&gt;Minimal visual noise, maximum clarity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Duolingo&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gamification based on retention data&lt;/li&gt;
&lt;li&gt;A/B tests everything (3-5 day cycles)&lt;/li&gt;
&lt;li&gt;Bright accents guide behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Shopify&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean merchant dashboard&lt;/li&gt;
&lt;li&gt;Regional payment method adaptation&lt;/li&gt;
&lt;li&gt;Onboarding optimized for activation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎯 The Controversial Part
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you design based on "beauty" or "speed to ship," AI will likely win.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Designers who focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User behavior patterns&lt;/li&gt;
&lt;li&gt;Business metrics
&lt;/li&gt;
&lt;li&gt;Strategic thinking&lt;/li&gt;
&lt;li&gt;Collaboration with developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...will be in the top 5% of the market.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Quick Implementation Checklist
&lt;/h2&gt;

&lt;p&gt;For your next feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; [ ] Define which metric this feature should improve
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Choose familiar patterns over novel ones
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add smooth transitions (not just instant state changes)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Ensure 4.5:1+ color contrast (WCAG AA)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Test with keyboard navigation
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add loading/error states with clear feedback
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Track actual usage metrics (not just launches)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Run quick A/B test (3-5 days, not months)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Adapt for regional patterns if targeting multiple markets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔮 Bottom Line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;2026 isn't about making prettier interfaces.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding behavior&lt;/li&gt;
&lt;li&gt;Moving metrics&lt;/li&gt;
&lt;li&gt;Building adaptable systems&lt;/li&gt;
&lt;li&gt;Collaborating strategically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI can generate the pixels. Developers + designers who understand the "why" behind the "what" will build products that actually work.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full deep-dive (18 min read):&lt;/strong&gt; &lt;a href="https://dev.family/blog/article/uxui-ai-and-trends-that-actually-work-in-2026" rel="noopener noreferrer"&gt;https://dev.family/blog/article/uxui-ai-and-trends-that-actually-work-in-2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's your experience?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are you tracking UX metrics in your projects?&lt;/li&gt;
&lt;li&gt;Have you adapted interfaces for different regions?&lt;/li&gt;
&lt;li&gt;How do you use AI in your design/dev workflow?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's discuss in the comments! 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. If you're building products and want to dive deeper into any of these patterns, happy to answer questions in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ux</category>
      <category>design</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to verify your cookie consent is working 🍪🍪</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 08 May 2025 07:59:28 +0000</pubDate>
      <link>https://dev.to/dev_family/how-to-verify-your-cookie-consent-is-working-i4f</link>
      <guid>https://dev.to/dev_family/how-to-verify-your-cookie-consent-is-working-i4f</guid>
      <description>&lt;p&gt;Got your cookie banner set up with Google Consent Mode? Now comes the critical step – verifying that it’s actually respecting user choices.&lt;/p&gt;

&lt;p&gt;Here’s how to ensure everything is working smoothly:&lt;br&gt;
1️⃣ Use Browser DevTools. Before and after consent, check cookies and requests to ensure compliance. Is Google Analytics firing only after consent? Are non-essential cookies blocked before? Make sure your users’ privacy is protected.&lt;br&gt;
2️⃣ Google Tag Assistant. This Chrome extension shows consent status changes in real time, so you can track whether analytics and ads are only enabled when users say "yes".&lt;/p&gt;

&lt;p&gt;And don’t forget about a detailed cookie policy that aligns with regional laws (GDPR, CCPA). &lt;/p&gt;

&lt;p&gt;📘 Learn more in &lt;a href="https://dev.family/blog/article/how-to-customize-the-consent-cookie-banner-to-comply-with-gdpr-google-consent-mode-and-country-specific-laws?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=max&amp;amp;utm_content=how-to-customize-the-consent-cookie-banner-to-comply-with-gdpr-google-consent-mode-and-country-specific-laws" rel="noopener noreferrer"&gt;our full guide&lt;/a&gt; with examples of cookie policy for EU and US&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>cookie</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Telegram mini-app development and testing specifics: from initialisation to launch</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Tue, 11 Mar 2025 10:58:06 +0000</pubDate>
      <link>https://dev.to/dev_family/telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch-1ofh</link>
      <guid>https://dev.to/dev_family/telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch-1ofh</guid>
      <description>&lt;p&gt;We receive more and more requests for Telegram mini apps development. Why is this happening? Telegram continues to grow actively, and companies want to reach this audience by offering convenient solutions within the messenger, where their customers spend a significant part of their time.&lt;br&gt;
The dev.family team has already talked about these and other benefits for business in one of &lt;a href="https://dev.family/blog/article/product-launch-on-messenger-apps-telegram-web-app-opportunities-for-businesses?utm_source=dev-to&amp;amp;utm_medium=article&amp;amp;utm_campaign=telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch&amp;amp;utm_content=product-launch-on-messenger-apps-telegram-web-app-opportunities-for-businesses" rel="noopener noreferrer"&gt;our articles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From a technical point of view, mini apps also have their advantages: they allow full-fledged applications to be launched directly in Telegram, without the need to develop separate native mobile versions. This significantly reduces development and support costs and speeds up the product's time to market.&lt;/p&gt;

&lt;p&gt;In this article, I will share my own experience of developing Telegram mini apps and answer the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are Telegram mini apps?&lt;/li&gt;
&lt;li&gt;How are they different from other platforms?&lt;/li&gt;
&lt;li&gt;What are the development prospects for Telegram mini apps?&lt;/li&gt;
&lt;li&gt;How to properly test Telegram mini apps, taking into account the peculiarities of the platform?&lt;/li&gt;
&lt;li&gt;How to set up the environment for a future application and initialise the Telegram apps SDK?&lt;/li&gt;
&lt;li&gt;What are the nuances of Telegram mini apps development?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What are Telegram mini apps and why are they so popular
&lt;/h2&gt;

&lt;p&gt;Today, Telegram mini apps allow us to open any website from within the messenger. The technology is implemented with the help of a special WebView browser shell – a system component that is responsible for integrating web pages into other applications and adapting to the device's operating system.&lt;/p&gt;

&lt;p&gt;A Telegram mini app can be any application that can be written in JavaScript or any tool that can be compiled into it. For example, React, Next.js, Angular or even React Native for Web.&lt;/p&gt;

&lt;p&gt;The product can either be a standalone solution or part of a business ecosystem. We have already told you in our &lt;a href="https://dev.family/blog/article/how-to-build-a-web-app-part-i-developing-on-react-native-web?utm_source=dev-to&amp;amp;utm_medium=article&amp;amp;utm_campaign=telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch&amp;amp;utm_content=how-to-build-a-web-app-part-i-developing-on-react-native-web" rel="noopener noreferrer"&gt;Telegram mini app tutorial &lt;/a&gt;how to integrate a ready-made React Native application into Telegram using the react-native-web package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development prospects for Telegram mini apps&lt;/strong&gt;&lt;br&gt;
The number of Telegram users is gradually approaching one billion. Imagine giving them access to a cross-browser application that runs on any operating system, be it iOS, Android, Windows, macOS or Linux. And it doesn't require any mobile development. Now you can add the mini app to the desktop of your device and open it full screen as a standalone application. And it seems we are only at the beginning of its development path.&lt;/p&gt;

&lt;p&gt;The functionality of Telegram mini apps and the possibility of integrating additional services and tools is quite wide: we can use accelerometer, gyroscope, biometrics, have access to geolocation, receive push notifications and much more.&lt;/p&gt;

&lt;p&gt;Of course, many things can be done using the standard browser API. But Telegram simplifies user interaction, permissions, payments, data exchange and bot management by providing all the necessary tools. And thanks to Telegram's built-in security, mini apps can be more secure than traditional web apps.&lt;/p&gt;

&lt;p&gt;I am sure that in the future Telegram will develop the mini apps format towards mobile development. There will be more and more opportunities to access the hardware features of devices, such as Bluetooth, NFC, Wi-Fi, flashlight, contacts, calendar and so on.&lt;/p&gt;

&lt;p&gt;Working with Telegram mini apps is also very convenient for the user: if the messenger is already installed on the device with a connected account, there is no need to download anything additional. All the functionalities are already available in Telegram.&lt;/p&gt;

&lt;p&gt;Businesses, in turn, get a convenient mobile app without having to resort to mobile development, which is usually more expensive than web development. Once we write an app competently, we can run it in the browser, mobile and desktop versions of Telegram, getting more opportunities and conversions for less cost.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to properly test and debug the Telegram mini app
&lt;/h2&gt;

&lt;p&gt;Let's go ahead and start with the peculiarities of testing Telegram mini apps, because we'll talk about them later in the development section. So it is important to set the context. The main difficulty is the inability to launch the project as easily as in a browser via localhost, and the lack of a developer console. However, these problems are easily solved.&lt;/p&gt;

&lt;p&gt;As we have already seen, the Telegram mini app is a website that, when linked to, will run in the Telegram environment. So we need to pass a link that displays the development environment. This is done using port forwarding.&lt;/p&gt;

&lt;p&gt;There are two ways of doing this.&lt;/p&gt;

&lt;p&gt;In the first case, we use the third-party utility ngrok. But it only has a monthly limit on the number of connections, so this option is not very suitable for development.&lt;/p&gt;

&lt;p&gt;In the second case we can use VSCode, where we need to open our project and run it as localhost. Next, open the terminal, go to the 'Ports' tab, type in the port number and you will get a link to the redirected port, which can now be used to access our localhost. We will use this link as the link to the mini app in the chatbot.&lt;br&gt;
It looks like this: &lt;a href="https://d0etr6gh-3000.euw.devtunnels.ms" rel="noopener noreferrer"&gt;https://d0etr6gh-3000.euw.devtunnels.ms&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A redirected port can be created as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private – no one but you will be able to access it;&lt;/li&gt;
&lt;li&gt;Public – the port will be available to everyone if we want to share the link to the application with others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0ij6zaa9coe2xnc24xr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0ij6zaa9coe2xnc24xr.png" alt="Image description" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we can launch our Telegram mini app and follow the development process in real time, because Hot Reload works just like in a browser.&lt;/p&gt;

&lt;p&gt;But how do you debug an application without access to the developer console? To do this, let's learn about Eruda.&lt;/p&gt;

&lt;p&gt;Eruda is a mobile development console that can be launched in any environment. All you need to do is click on the button that is embedded in your application after initialising this library.&lt;br&gt;
This is what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwx5dvu9yw9ld45i78q0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwx5dvu9yw9ld45i78q0.png" alt="Image description" width="714" height="1398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcotktw1zuf5nylr67ntx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcotktw1zuf5nylr67ntx.png" alt="Image description" width="716" height="1394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filmo28jfsaamwx1jimkv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filmo28jfsaamwx1jimkv.png" alt="Image description" width="718" height="1414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1d08r24fegoqg48oy4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1d08r24fegoqg48oy4n.png" alt="Image description" width="732" height="1206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below we'll go through how to create a mini app in Telegram from scratch and set up an initial template to initialise the &lt;strong&gt;telegram-apps/sdk-react package&lt;/strong&gt; and the app itself. We will see how easy it is to integrate the Eruda package into our project.&lt;/p&gt;

&lt;p&gt;You can also read the documentation and connect the package in a different way. Either way, it will only take a few lines of string.&lt;br&gt;
In addition, I would like to mention one more thing that relates to testing.&lt;/p&gt;

&lt;p&gt;If you try to open the app in a browser, you will see the following error:&lt;br&gt;
&lt;em&gt;&lt;strong&gt;“Unable to retrieve launch parameters from any known source. Perhaps, you have opened your app outside Telegram?”&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fff6wy3z3sowiwl1ale9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fff6wy3z3sowiwl1ale9j.png" alt="Image description" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The message says that the mini app cannot be launched outside the Telegram environment.&lt;/p&gt;

&lt;p&gt;Let's move from theory to practice.&lt;/p&gt;

&lt;p&gt;However, we can configure our application to open in a browser. We will not be able to get real data from Telegram, but we will add mock data that will mimic the environment we need.&lt;/p&gt;
&lt;h2&gt;
  
  
  Development of Telegram mini app from scratch
&lt;/h2&gt;

&lt;p&gt;We have already described the process of creating a chatbot in Telegram using BotFather in &lt;a href="https://dev.family/blog/article/how-to-build-a-web-app-part-ii-deploying-telegram-mini-app?utm_source=dev-to&amp;amp;utm_medium=article&amp;amp;utm_campaign=telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch&amp;amp;utm_content=how-to-build-a-web-app-part-ii-deploying-telegram-mini-app" rel="noopener noreferrer"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So let's move on to the code itself.&lt;/p&gt;

&lt;p&gt;The next step is to initialise the mini app project. In general, the Telegram developers have gone to the trouble of preparing a selection of &lt;a href="https://github.com/Telegram-Mini-Apps#templates" rel="noopener noreferrer"&gt;ready-made template&lt;/a&gt; that you can use depending on the technology. For example, here are variants for &lt;a href="https://github.com/Telegram-Mini-Apps/nextjs-template" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; and &lt;a href="https://github.com/Telegram-Mini-Apps/reactjs-template" rel="noopener noreferrer"&gt;React.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;✍ Does it make sense to use Next.js? Unfortunately, mini apps are not currently able to fully adapt to SSR, ISR and other rendering methods. Communication with Telegram happens through the use of a window object, which is impossible to get on the server side.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So if your application involves user identification or a chatbot, you will not be able to do this on the server and queries will have to be executed on the client. However, this does not change the fact that Next.js has additional benefits, features and optimisations over React and can still be used for mini app development.&lt;/p&gt;

&lt;p&gt;Let's go back to the code. We took one of the ready-made templates and adapted it for our purposes, removing anything unnecessary and adding additional logic. To work with Telegram mini apps, we used the &lt;strong&gt;@telegram-apps/sdk-react package&lt;/strong&gt;. Let's talk about it in a bit more detail.&lt;/p&gt;

&lt;p&gt;We have a provider that is used in the root barkout to initialise this package and wrap the whole app.&lt;/p&gt;

&lt;p&gt;It looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html lang={locale} className={`${GeologicaFont.variable}`}&amp;gt;
&amp;lt;body&amp;gt;
         &amp;lt;TelegramSDKInitProvider&amp;gt;
           &amp;lt;AppInitProvider&amp;gt;
               &amp;lt;div className={styles.layout}&amp;gt;{children}&amp;lt;/div&amp;gt;
           &amp;lt;/AppInitProvider&amp;gt;
         &amp;lt;/TelegramSDKInitProvider&amp;gt;
     &amp;lt;/body&amp;gt;
   &amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens here and why do we need two providers?&lt;/p&gt;

&lt;p&gt;First, all the logic is executed inside TelegramSDKInitProvider: the package is initialised so that we can get the user data and use the Telegram API in our application. We check the environment and mock the data if we are in development mode. This is to imitate the Telegram environment to run the application in the browser.&lt;/p&gt;

&lt;p&gt;If we are in a production environment, it makes more sense to show an error or inform the user that the app needs to run inside Telegram. And ideally, add a link and QR code to the interface to go directly to the messenger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'

import { type PropsWithChildren } from 'react'

import { useClientOnce } from '@/src/hooks/useClientOnce'
import { useTelegramMock } from '@/src/hooks/useTelegramMock'

import { telegramSDKInit } from './init'

export function TelegramSDKInitProvider({ children }: PropsWithChildren) {
 if (process.env.NODE_ENV === 'dev') {
   useTelegramMock()
 }

 useClientOnce(() =&amp;gt; {
   telegramSDKInit(false)
 })

 return children
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the &lt;strong&gt;useTelegramMock&lt;/strong&gt; hook we use a check provided by the package itself – &lt;strong&gt;isTMA&lt;/strong&gt;. This allows us to determine if we are in the Telegram environment. If we are not, we mock the data, if we are, we exit the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { isTMA, mockTelegramEnv, parseInitData } from '@telegram-apps/sdk-react'

import { useClientOnce } from './useClientOnce'

export function useTelegramMock(): void {
 useClientOnce(() =&amp;gt; {
   let shouldMock: boolean
   const MOCK_KEY = '____mocked'

   if (isTMA('simple')) {
     shouldMock = !!sessionStorage.getItem(MOCK_KEY)
   } else {
     shouldMock = true
   }

   if (!shouldMock) {
     return
   }

   const initDataRaw = new URLSearchParams([
     [
       'user',
       JSON.stringify({
         id: 99281932,
         first_name: 'Arthur',
         last_name: 'Mocked',
         username: 'arthurmocked',
         language_code: 'en',
         is_premium: true,
         allows_write_to_pm: true,
         photoUrl:
           'https://t.me/i/userpic/320/haNXSpRmeucJyo-oXFbNrifxZ-Au0PjvhpJ2l6h4ozcTbTT8yvNKIZABSCLpjtIp.svg',
       }),
     ],
     ['hash', '89d6079ad6762351f38c6dbbc41bb53048019256a9443988af7a48bcad16ba31'],
     ['auth_date', '1716922846'],
     ['start_param', 'debug'],
     ['chat_type', 'sender'],
     ['chat_instance', '8428209589180549439'],
   ]).toString()

   mockTelegramEnv({
     themeParams: {
       accentTextColor: '#6ab2f2',
       bgColor: '#17212b',
       buttonColor: '#5288c1',
       buttonTextColor: '#ffffff',
       destructiveTextColor: '#ec3942',
       headerBgColor: '#17212b',
       hintColor: '#708499',
       linkColor: '#6ab3f3',
       secondaryBgColor: '#232e3c',
       sectionBgColor: '#17212b',
       sectionHeaderTextColor: '#6ab3f3',
       subtitleTextColor: '#708499',
       textColor: '#f5f5f5',
     },
     initData: parseInitData(initDataRaw),
     initDataRaw,
     version: '8',
     platform: 'tdesktop',
   })
   sessionStorage.setItem(MOCK_KEY, '1')

   console.info(
     '⚠️ As long as the current environment was not considered as the Telegram-based one, it was mocked. Take a note, that you should not do it in production and current behavior is only specific to the development process. Environment mocking is also applied only in development mode. So, after building the application, you will not see this behavior and related warning, leading to crashing the application outside Telegram.',
   )
 })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use our own data. For example, from your Telegram account.&lt;br&gt;
Now we can run our app both in Telegram and in any browser.&lt;/p&gt;

&lt;p&gt;Next, we run &lt;strong&gt;telegramSDKInit&lt;/strong&gt;, which initialises the SDK package and performs the initial configuration of the application. For example, configuring the full screen mode or the behaviour of closing the app with vertical swipes.&lt;/p&gt;

&lt;p&gt;This is also where we initialise the Eruda mobile console that I mentioned in the testing section. The initialisation happens only once – when the app is launched, which is controlled by the &lt;strong&gt;useClientOnce&lt;/strong&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
 $debug,
 backButton,
 expandViewport,
 init as initSDK,
 initData,
 miniApp,
 swipeBehavior,
 themeParams,
 viewport,
} from '@telegram-apps/sdk-react'

export function telegramSDKInit(debug: boolean): void {
 $debug.set(debug)

 initSDK()
 expandViewport()

 if (backButton.isSupported()) {
   backButton.mount()
 }

 miniApp.mount()
 themeParams.mount()
 swipeBehavior.mount()
 initData.restore()

 void viewport
   .mount()
   .then(() =&amp;gt; {
     viewport.bindCssVars()
     miniApp.bindCssVars()
     themeParams.bindCssVars()
     viewport.requestFullscreen()
     swipeBehavior.disableVertical()
   })
   .catch((e: unknown) =&amp;gt; {
     console.error('Something went wrong mounting the viewport', e)
   })

 debug &amp;amp;&amp;amp; import('eruda').then((lib) =&amp;gt; lib.default.init()).catch(console.error)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the &lt;strong&gt;AppInitProvider&lt;/strong&gt; logic is executed, where we show the download status instead of the content, as our app is not ready to use yet. Here we already have access to the Telegram API, so we get the data we need (e.g. user data). Next, we will either record the user ID in cookies or perform an authorisation request, passing the necessary data from Telegram.&lt;/p&gt;

&lt;p&gt;Once all the manipulations are done, we can display the rest of the application.&lt;/p&gt;

&lt;p&gt;An AppInitProvider could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'

import { initData, useSignal } from '@telegram-apps/sdk-react'
import { setCookie } from 'cookies-next'
import type { PropsWithChildren } from 'react'
import { useCallback, useEffect, useState } from 'react'

import { postAuthLogin } from '@/src/api/schema'
import TelegramMiniAppLoader from '@/src/components/ui/TelegramMiniAppLoader'
import Title from '@/src/components/ui/Title'
import { AUTH_TOKEN, TELEGRAM_USER_ID } from '@/src/constants'

const AppInitProvider = ({ children }: PropsWithChildren) =&amp;gt; {
 const [isAppReady, setIsAppReady] = useState(false)
 const [error, setError] = useState(null)

 const initDataState = useSignal(initData.state)
 const initDataStateRaw = useSignal(initData.raw)

 const userId = initDataState?.user?.id

 const logError = useCallback((message: string) =&amp;gt; {
   console.error(message)
   setError(message)
 }, [])

 const authenticateUser = useCallback(
   async (rawData: string) =&amp;gt; {
     try {
       const { data } = await postAuthLogin({ init_data: rawData })

       if (data) {
         setCookie(AUTH_TOKEN, data.token)
         setIsAppReady(true)
       } else {
         logError(`Auth token is missing. Response: ${JSON.stringify(data)}`)
       }
     } catch (err) {
       logError(
         `Authentication failed: ${err instanceof Error ? err.message : JSON.stringify(err, null, 2)}`,
       )
     }
   },
   [logError],
 )

 const initApp = useCallback(() =&amp;gt; {
   if (!userId) {
     logError(`Telegram user ID is absent. User ID: ${userId}`)
     return
   }

   setCookie(TELEGRAM_USER_ID, userId)

   if (!initDataStateRaw) {
     logError('Telegram raw data is undefined.')
     return
   }

   authenticateUser(initDataStateRaw)
 }, [userId, initDataStateRaw, authenticateUser, logError])

 useEffect(() =&amp;gt; {
   console.log('Initializing app with raw data:', initDataStateRaw)
   initApp()
 }, [initApp, initDataStateRaw])

 if (error) {
   return {error}
 }

 return isAppReady ? &amp;lt;&amp;gt;{children} : 
}

export default AppInitProvider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our application is now fully initialised and ready to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Specifics of Telegram mini app development
&lt;/h2&gt;

&lt;p&gt;Let's look at the key issues and challenges you need to understand to ensure a stable application and user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebView limitations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since Telegram mini apps are based on the WebView interface, not all of the features we use in browsers will work here.&lt;/p&gt;

&lt;p&gt;In our app we use iFrame. And if we want to open it in full screen, we can use the &lt;strong&gt;requestFullScreen&lt;/strong&gt; method. Unfortunately, this doesn't work for WebView. Also, some icons may display differently or not at all. Especially if gradients are used inside. Problems can also occur when using WebSocket, which might requires additional configuration. It is therefore important to spend extra time on development to fix any bugs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3buyirb2jdcpqtvphfv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3buyirb2jdcpqtvphfv.png" alt="Image description" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, I have often seen comments on forums that using WebView causes performance degradation. Especially on low-power devices and when there are a lot of complex animations. Some developers even include the ability to disable animations in the app so users don't experience performance issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency on Telegram API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Despite the popularity of Telegram, the platform also has its own bugs that can affect your app. Here's a case study example.&lt;br&gt;
Telegram automatically handles situations where a virtual keyboard is opened on mobile devices and automatically moves content so that they do not overlap. On the one hand, this is very convenient – developers don't have to write additional logic if, for example, the input field is at the bottom of the screen. On the other hand, at the time of writing, this feature still does not work correctly on iOS devices, which can lead to some limitations for users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitation in working with query parameters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you try to pass initial parameters to a mini app link, Telegram will simply cut them out. According to the Telegram mini app documentation, we can only pass one parameter called startapp. The process looks like this: &lt;a href="https://t.me/botusername/appname?startapp=someParamValue" rel="noopener noreferrer"&gt;https://t.me/botusername/appname?startapp=someParamValue&lt;/a&gt;&lt;br&gt;
But if you need to pass multiple parameters, you can use the following trick: we still pass one parameter in the reference, but it has many other parameters nested within it with a specific delimiter. For example, '_ _'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://t.me/botusername/appname?startapp=param1value__param2value__par
am3value
const [param1, param2, param3] = lp.startParam.split("__");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Client-side nature of app&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is also important to remember that mini apps run primarily on the client side. This limits the use of server-side rendering (SSR), because to use the Telegram API you need access to the window object, which is only available on the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peculiarities of the Telegram platform
&lt;/h2&gt;

&lt;p&gt;To create a Telegram mini app, you need to understand the specifics of the platform itself and the specifics of working with WebView.&lt;br&gt;
For beginners, I recommend to pay attention to the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Telegram WebApp API&lt;/strong&gt; – interact with buttons, events, get user data. Study the library documentation if you plan to use it to work with Telegram;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission handling&lt;/strong&gt; – proper handling of initData and signature verification. Authorisation is taken to a new level here, eliminating the need to constantly create and store tokens on the client side;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform limitations&lt;/strong&gt; – specifics of rendering, navigation and integration with front-end frameworks (e.g. Next.js);&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interface customisation – working with dark and light themes, WebView customisation, and developing workarounds for platform limitations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;✍ This may seem complicated and time-consuming, but learning new things is an important part of being a programmer. In the future, Telegram will certainly continue to develop its API and expand support for device hardware capabilities.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The sooner you start working with this format, the sooner you'll learn to develop cross-platform solutions, get a deeper understanding of external API integration, and gain experience with scalable applications for an audience of billions.&lt;/p&gt;

&lt;p&gt;The dev.family team has been in touch 💜💚&lt;br&gt;
See you soon!&lt;/p&gt;

&lt;p&gt;P.S. As per tradition, here are the links to the artefacts:&lt;br&gt;
Telegram mini apps documentation: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://core.telegram.org/bots/webapps" rel="noopener noreferrer"&gt;https://core.telegram.org/bots/webapps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The documentation of the package for interacting with the Telegram API is telegram-apps/sdk-react: &lt;a href="https://docs.telegram-mini-apps.com/packages/telegram-apps-sdk-react/2-x" rel="noopener noreferrer"&gt;https://docs.telegram-mini-apps.com/packages/telegram-apps-sdk-react/2-x&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Templates from Telegram developers: &lt;a href="https://github.com/Telegram-Mini-Apps#templates" rel="noopener noreferrer"&gt;https://github.com/Telegram-Mini-Apps#templates&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telegram mini apps template for Next.js: &lt;a href="https://github.com/Telegram-Mini-Apps/nextjs-template" rel="noopener noreferrer"&gt;https://github.com/Telegram-Mini-Apps/nextjs-template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telegram mini apps template for React.js. &lt;a href="https://github.com/Telegram-Mini-Apps/reactjs-template" rel="noopener noreferrer"&gt;https://github.com/Telegram-Mini-Apps/reactjs-template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Eruda documentation: &lt;a href="https://github.com/liriliri/eruda" rel="noopener noreferrer"&gt;https://github.com/liriliri/eruda&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ngrok: &lt;a href="https://ngrok.com/docs/pricing-limits/free-plan-limits/" rel="noopener noreferrer"&gt;https://ngrok.com/docs/pricing-limits/free-plan-limits/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to add a card to Apple Wallet and Google Wallet 📱 in React Native?</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 07 Nov 2024 12:30:21 +0000</pubDate>
      <link>https://dev.to/dev_family/how-to-add-a-card-to-apple-wallet-and-google-wallet-in-react-native-4keb</link>
      <guid>https://dev.to/dev_family/how-to-add-a-card-to-apple-wallet-and-google-wallet-in-react-native-4keb</guid>
      <description>&lt;p&gt;Mobile developers can use Apple Wallet and Google Wallet integrations for different types of apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Boarding pass storage and hotel reservations;&lt;/li&gt;
&lt;li&gt;Card for short-term rental;&lt;/li&gt;
&lt;li&gt;Passes for buildings or events;&lt;/li&gt;
&lt;li&gt;Scan tickets for travel or subscriptions;&lt;/li&gt;
&lt;li&gt;Store loyalty cards and gift vouchers;&lt;/li&gt;
&lt;li&gt;Providing contactless payment, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we already wrote our own library for Apple Wallet in React Native because we couldn't find anything ready to use. As true open source enthusiasts, we have already shared &lt;a href="https://medium.com/@dev.family/how-to-add-a-card-to-apple-wallet-in-react-native-ae966c2e7567" rel="noopener noreferrer"&gt;this version&lt;/a&gt; with you. But now that Google Wallet is fully released, it's time to update it.&lt;/p&gt;

&lt;p&gt;Now, this library provides integration with both Apple Wallet on iOS and Google Wallet on Android. It allows you to add, remove, and check for existing passes on iOS, and add passes to Google Wallet on Android. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dev-family/react-native-wallet-manager" rel="noopener noreferrer"&gt;&lt;strong&gt;Readme&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To download the library go&lt;/strong&gt; &lt;a href="https://github.com/dev-family/react-native-wallet-manager" rel="noopener noreferrer"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You can find out more about disruptive with React Native you’ll find in &lt;a href="https://dev.family/blog/categories/mobile?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=blog-categories-mobile&amp;amp;utm_term=how-to-add-a-card-to-apple-wallet" rel="noopener noreferrer"&gt;our blog&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to build a Web App: Deploying Telegram mini-app</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 31 Oct 2024 14:45:33 +0000</pubDate>
      <link>https://dev.to/dev_family/how-to-build-a-web-app-deploying-telegram-mini-app-272e</link>
      <guid>https://dev.to/dev_family/how-to-build-a-web-app-deploying-telegram-mini-app-272e</guid>
      <description>&lt;p&gt;Hi there, it's the &lt;a href="https://dev.family/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=main&amp;amp;utm_term=how-to-build-a-web-app-part-ii-deploying-telegram-mini-app" rel="noopener noreferrer"&gt;dev.family team&lt;/a&gt; again! We're continuing our experiment with building an app in React Native that works as as a Telegram Web App. In our previous episodes, we discussed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The specifics of building a React Native web application using react-native-web and where we deviated from the documentation. You can find all the code and details of the process in &lt;a href="https://dev.family/blog/article/how-to-build-a-web-app-part-i-developing-on-react-native-web?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=how-to-build-a-web-app-part-i-developing-on-react-native-web&amp;amp;utm_term=how-to-build-a-web-app-part-ii-deploying-telegram-mini-app" rel="noopener noreferrer"&gt;the first part&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The reasons &lt;a href="https://dev.family/blog/article/product-launch-on-messenger-apps-telegram-web-app-opportunities-for-businesses?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=product-launch-on-messenger-apps-telegram-web-app-opportunities-for-businesses&amp;amp;utm_term=how-to-build-a-web-app-part-ii-deploying-telegram-mini-app" rel="noopener noreferrer"&gt;why companies choose to run web applications on messenger apps&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's focus on installing the web app itself within the Telegram bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web AppDeployment
&lt;/h2&gt;

&lt;p&gt;In the last part we finished the preparatory work. Now let's deploy our site.&lt;/p&gt;

&lt;p&gt;We will use Firebase to deploy the clicker. There are two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first (and easiest) is a simple command line deploy;&lt;/li&gt;
&lt;li&gt;The second (a bit more complicated) is a commit/merge/PR deploy via github actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the purposes of this article, let's look at the fastest option.&lt;/p&gt;

&lt;p&gt;Let's create a project in the Firebase Console. Follow &lt;a href="https://console.firebase.google.com/" rel="noopener noreferrer"&gt;the link&lt;/a&gt; and click on the 'Create Project' button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7tu3tm2x4wquga6m1x0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7tu3tm2x4wquga6m1x0.png" alt="Image description" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify the name of our project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65dsc35oun29c1ydi6o9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65dsc35oun29c1ydi6o9.png" alt="Image description" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, click ‘Continue’ several times, select Default Firebase Account (if you have a different one, you can select it), and click Create Project.&lt;/p&gt;

&lt;p&gt;The new project is successfully established:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqahelbrogl9rx8qcnu5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqahelbrogl9rx8qcnu5z.png" alt="Image description" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now go to the project and click the 'Add Web Application' button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiu0dhr8k7wh22qmh0u49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiu0dhr8k7wh22qmh0u49.png" alt="Image description" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, enter the name of the project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1oiwmnplid5saia7tm7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1oiwmnplid5saia7tm7.png" alt="Image description" width="742" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can leave the 'Set up Firebase hosting too' checkbox unchecked. Click on the 'Register application' button and you will see two options with instructions on how to install the Firebase tools in our project.&lt;/p&gt;

&lt;p&gt;We won't use the option via npm, but via the script tag, as we don't need it for the mobile application. You can choose any convenient option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuqo9lyju1n9urjealwbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuqo9lyju1n9urjealwbw.png" alt="Image description" width="800" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This completes our work with Firebase Console, let's return to the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: It is not recommended to put all these keys directly in the html file. It is better to create an .env file and put them there.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.env&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=
VITE_FIREBASE_STORAGE_BUCKET=
VITE_FIREBASE_MESSAGING_SENDER_ID=
VITE_FIREBASE_APP_ID=
VITE_FIREBASE_MEASUREMENT_ID=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that all of the keys we use start with the word ‘Vite’. We do this because we are using Vite as an assembler. And when accessing environment variables via import.meta.env, it may not recognise them without this.&lt;/p&gt;

&lt;p&gt;Next, let's edit our index.html a bit, taking into account what we've written above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.html&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
...
&amp;lt;script type="module"&amp;gt;
 import { initializeApp } from "https://www.gstatic.com/firebasejs/10.13.0/firebase-app.js";
 import { getAnalytics } from "https://www.gstatic.com/firebasejs/10.13.0/firebase-analytics.js";
  const firebaseConfig = {
   apiKey:import.meta.env.VITE_FIREBASE_API_KEY,
   authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
   projectId:  import.meta.env.VITE_FIREBASE_PROJECT_ID,
   storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
   messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
   appId: import.meta.env.VITE_FIREBASE_APP_ID,
   measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
 };


 const app = initializeApp(firebaseConfig);
 const analytics = getAnalytics(app);
&amp;lt;/script&amp;gt;
&amp;lt;script src="./index.web.js" type="module"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a terminal, go to the root of the project and type the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we go to the browser window and authorise through the Firebase console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select the highlighted item and press Space, then Enter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6tmoeasebvozcag85uff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6tmoeasebvozcag85uff.png" alt="Image description" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to resolve a number of configuration issues. Add the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Please select an option – here we select &lt;strong&gt;Use an existing project&lt;/strong&gt;. And from the list below – a recently created project;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What do you want to use as your public directory? – select &lt;strong&gt;dist&lt;/strong&gt; (this is where our unit will be located);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure as a single-page app (rewrite all urls to /index.html)? – &lt;strong&gt;y&lt;/strong&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up automatic builds and deploys with GitHub? (y/N) – &lt;strong&gt;N&lt;/strong&gt; (we don't need it at this stage);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;File dist/index.html already exists. Overwrite? (y/N) – &lt;strong&gt;N&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go to firebase.json and modify it a bit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;firebase.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"hosting": {
   "public": "dist",
   "ignore": [
     "firebase.json",
     "**/.*",
     "**/node_modules/**",
     //past here
     "**/android/**",
     "**/ios/**"
   ],
   "rewrites": [
     {
       "source": "**",
       "destination": "/index.html"
     }
   ]
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the Android and iOS directories to ignore during deployment. Since we have a web application, we don't need to send all the files to a hosting service. Also, they're quite heavy and you won't be able to download them without some sort of subscription.&lt;/p&gt;

&lt;p&gt;So, we're nearing the finish line. There's just one more command to write.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;firebase deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12ncb8hbi74q9z94l4q2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12ncb8hbi74q9z94l4q2.png" alt="Image description" width="796" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click on the link below. Our application is already hosted!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjshvutt5ondi9ycg99hk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjshvutt5ondi9ycg99hk.png" alt="Image description" width="800" height="865"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All you have to do is deploy the app on Telegram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing a web app in a Telegram bot
&lt;/h2&gt;

&lt;p&gt;Let's take a look at what's currently available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A working app on iOS;&lt;/li&gt;
&lt;li&gt;A working app on Android;&lt;/li&gt;
&lt;li&gt;A working web app, already hosted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With one last tap, you can add an app to the list in a messenger app. Open a bot called BotFather in Telegram and start a dialogue.&lt;/p&gt;

&lt;p&gt;Choose the option /newbot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cq0qoub087bfsjvxy13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cq0qoub087bfsjvxy13.png" alt="Image description" width="800" height="713"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give our bot a name. This will create an API key for interacting with our bot via HTTP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx8chqrdoj35yasix8ux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx8chqrdoj35yasix8ux.png" alt="Image description" width="800" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, write the command /mybots and choose the currently created bot. Go to &lt;strong&gt;bot settings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qf234z8v2bpp6jrjwdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qf234z8v2bpp6jrjwdc.png" alt="Image description" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose the point &lt;strong&gt;Configure Mini App&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77wsrpyaiw6n2dq7t2p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77wsrpyaiw6n2dq7t2p8.png" alt="Image description" width="788" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may see a message saying that the Mini App is disabled for our Telegram bot. That's fine. Just click on the &lt;strong&gt;Enable Mini App&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu1u0xuqemtl11iwo5ffc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu1u0xuqemtl11iwo5ffc.png" alt="Image description" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we just pass the URL where our web application is hosted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhbmhemvdvnl7jln9etn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhbmhemvdvnl7jln9etn.png" alt="Image description" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's configure the menu button. To do this, go back to the bot settings and select Configure Menu Button. Again, you may be told that the button is currently disabled and offered the option to enable it. Accept and give it a name.&lt;/p&gt;

&lt;p&gt;The time has come: let's see how our guy works. Let's go to the bot – &lt;a href="https://t.me/ReactNativeWebClickerBot" rel="noopener noreferrer"&gt;@ReactNativeWebClickerBot&lt;/a&gt; (you can rate it too, we'd appreciate it 😌). We open it up and make sure it works!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffgm0ini2ix2qbx03cgz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffgm0ini2ix2qbx03cgz4.png" alt="Image description" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All theme settings are synchronised, as is the username. If you enter the bot from the mobile app and click on a coin, you can feel how well the haptic response works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this experiment, we break down in detail how you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a web app based on a mobile app written in React Native using react-native-web;&lt;/li&gt;
&lt;li&gt;Deploy it via Firebase;&lt;/li&gt;
&lt;li&gt;Use it in a Telegram mini-app;&lt;/li&gt;
&lt;li&gt;Interoperate with the Telegram client in our shared codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The technologies described can be used not only for Telegram, but also for other platforms. So you can create cross-platform solutions that work on the same code.&lt;/p&gt;

&lt;p&gt;Why it's good:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app will work across channels and be featured in multiple stores, allowing you to reach more users;&lt;/li&gt;
&lt;li&gt;The speed of product development will increase significantly – the average time to release will be reduced by 20%, meaning a faster time to market;&lt;/li&gt;
&lt;li&gt;Most of the code base can be reused, making updates and bug fixes easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main thing is to remember the specifics of each platform and take them into account when developing.&lt;/p&gt;

&lt;p&gt;We've deliberately left some parts of the code unwritten so that you can fill them in yourself. If you like, add Telegram user validation, check if the user is present in the mobile app and set up a Firebase deployment via GitHub Actions. In short, experiment to get the best results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As usual, we leave links to the useful resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://necolas.github.io/react-native-web/docs/" rel="noopener noreferrer"&gt;React Native Web&lt;/a&gt; documentation;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://core.telegram.org/bots/webapps#hapticfeedback" rel="noopener noreferrer"&gt;Telegram mini-app&lt;/a&gt; documentation;&lt;/li&gt;
&lt;li&gt;Link to &lt;a href="https://console.firebase.google.com/?pli=1" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;All code in &lt;a href="https://github.com/dev-family/react-native-web-example" rel="noopener noreferrer"&gt;Github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://t.me/ReactNativeWebClickerBot" rel="noopener noreferrer"&gt;@ReactNativeWebClickerBot&lt;/a&gt; itself.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>What if we told you that you don't need an app or a website to sell online? Go to Messenger and launch your Telegram WebApp.</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 24 Oct 2024 16:26:56 +0000</pubDate>
      <link>https://dev.to/dev_family/what-if-we-told-you-that-you-dont-need-an-app-or-a-website-to-sell-online-go-to-messenger-and-launch-your-telegram-webapp-4m4f</link>
      <guid>https://dev.to/dev_family/what-if-we-told-you-that-you-dont-need-an-app-or-a-website-to-sell-online-go-to-messenger-and-launch-your-telegram-webapp-4m4f</guid>
      <description>&lt;p&gt;Companies are moving to web apps in messengers. And here are the reasons why you should join them: &lt;br&gt;
🟣 Increase market share by entering the channel with a constantly active audience; &lt;br&gt;
🟢 Boost sales with an easy ordering process in just a few clicks; &lt;br&gt;
⚪️ Keep users engaged by communicating with them in one channel. &lt;/p&gt;

&lt;p&gt;It only takes a few seconds for customers to order food from the restaurant, pay for services and book the time to visit your establishment in messengers like WhatsApp or WeChat. Find more ideas for web applications in &lt;a href="https://dev.family/blog/article/how-to-build-a-web-app-part-i-developing-on-react-native-web" rel="noopener noreferrer"&gt;our article&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🎮 Writing in React Native and want to add cool game mechanics or AR/VR features to your app? It's easy to do with Unity.</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Fri, 20 Sep 2024 10:11:13 +0000</pubDate>
      <link>https://dev.to/dev_family/writing-in-react-native-and-want-to-add-cool-game-mechanics-or-arvr-features-to-your-app-its-easy-to-do-with-unity-2pg</link>
      <guid>https://dev.to/dev_family/writing-in-react-native-and-want-to-add-cool-game-mechanics-or-arvr-features-to-your-app-its-easy-to-do-with-unity-2pg</guid>
      <description>&lt;p&gt;Hello everyone! 👋 It's the &lt;a href="https://dev.family/?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=mail&amp;amp;utm_term=integrating-unity-code-into-react-native" rel="noopener noreferrer"&gt;dev.family team&lt;/a&gt; again with a rather unusual topic. Let's talk about games 🎮. More specifically, how to integrate Unity with React Native.&lt;/p&gt;

&lt;p&gt;📱 In our latest blog post, we've put together a step-by-step guide on how to seamlessly integrate Unity into your cross-platform mobile applications.&lt;/p&gt;

&lt;p&gt;We cover everything from initial setup to potential challenges you may face along the way. This guide has got you covered. ✅&lt;/p&gt;

&lt;p&gt;If you're curious and want to learn more, check out the full integration guide 🌐 &lt;a href="https://dev.family/blog/article/integrating-unity-code-into-react-native?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=integrating-unity-code-into-react-native" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>React Native Splash Screen - support for different themes</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 19 Sep 2024 14:45:57 +0000</pubDate>
      <link>https://dev.to/dev_family/react-native-splash-screen-support-for-different-themes-lb5</link>
      <guid>https://dev.to/dev_family/react-native-splash-screen-support-for-different-themes-lb5</guid>
      <description>&lt;p&gt;Hello everyone! It's the &lt;a href="https://dev.family/?utm_source=dev-to&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=mail&amp;amp;utm_term=react-native-splash-screen-support-for-different-themes" rel="noopener noreferrer"&gt;dev.family&lt;/a&gt; team is in touch. In this article, we are sharing a short guide on how to install Splash Screen in a cross-platform app written in React Native with support for multiple themes.&lt;/p&gt;

&lt;p&gt;Splash screen is the first screen that users see before loading into the main application. This screen is perhaps the best way to make the name of your app, and in general, its entire name, more memorable.&lt;/p&gt;

&lt;p&gt;But this is not the main role of the splash screen. Under it, for example, you can hide receiving data from the API and loading the main application. We do this when we show the loader on the screen when loading the same data. This allows you to improve the UX and immediately demonstrate the finished application to the user. And as a result, remove the extra loader when opening it for the first time.&lt;/p&gt;

&lt;p&gt;In this short guide, we will look at installing splash screens for iOS and Android using the react-native framework using the react-native-splash-screen library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-step instruction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Preparations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add react-native-splash-screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, in the ios folder you need to run the command to install the pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ios &amp;amp;&amp;amp; pod install &amp;amp;&amp;amp; cd ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(go to the ios directory, install pods and go back)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, there are two configuration options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use for the splash screen an image exported, for example, from the same Figma&lt;/li&gt;
&lt;li&gt;Making this screen by hand is more difficult and takes longer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's first look at the screen itself.&lt;/p&gt;

&lt;p&gt;Let's say we chose the option when a picture is used. We export it in high resolution (in our case x3). But, since we are doing everything for two themes at once, we need to export both copies (for light and dark). Next, go to AppIcon and drag first one image, then another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqycq20kxad6q3r0ilim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqycq20kxad6q3r0ilim.png" alt="Image description" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click Generate, download the assets and place them in the assets folder in the project root.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2kb7psicqgqfdgyrnu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2kb7psicqgqfdgyrnu3.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;НNow that the general preparations are complete, let’s move on directly to installation in the mobile application. Let's start with iOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Splash Screen iOS
&lt;/h2&gt;

&lt;p&gt;First of all, open the .xcworkspace of our project. There we see an empty AppIcon (if you did not add an application icon or other assets). Now let's create an image set file. Let's call it, for example, SplashScreen (yes, it’s very original, I know :))&lt;/p&gt;

&lt;p&gt;After creation, in the settings we see Apperances with the None option selected. Click on it and select Any, Light, Dark. In Any and Light we drag assets for the light iOS theme. In Dark - for dark, respectively. It turns out like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5cta9mvpn57pp4dujka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5cta9mvpn57pp4dujka.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’re almost there.&lt;/p&gt;

&lt;p&gt;Open &lt;em&gt;LaunchScreen.storyboard. Select View Controller Scene &amp;gt; View Controller &amp;gt; View&lt;/em&gt; and delete everything from there. After that, select View, click on the triangle icon at the top right and uncheck &lt;em&gt;Layout Guides &amp;gt; Safe Area&lt;/em&gt;. Click on the plus and add it to our View Image View. Remove all margins and check the &lt;em&gt;Constraints to margins&lt;/em&gt; checkbox.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqadq3yg6b2om7axfhi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqadq3yg6b2om7axfhi4.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the settings, we specify the resource for our Splash Screen. And select Content View, which suits us best. In this case - Scale To Fill. But Aspect Fit is suitable for most.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s8of7izk21io9dhu3ro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s8of7izk21io9dhu3ro.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can view the dark theme and check that the picture has changed correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffbb1fam24tbkt0cfqtpz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffbb1fam24tbkt0cfqtpz.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've sorted out the easy part of installing on iOS.&lt;/p&gt;

&lt;p&gt;As for the difficult one, everything is much more fun. I cannot provide a ready-made solution. You will have to export all the pictures and colors that make up your Splash Screen yourself, and customize LaunchScreen.storyboard manually.&lt;/p&gt;

&lt;p&gt;We'll show you how we do it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxzn265zxb1yz04kbw7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxzn265zxb1yz04kbw7h.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dbne2nkab6qecr279yx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dbne2nkab6qecr279yx.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3el2gz4mc0c9spyhk56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3el2gz4mc0c9spyhk56.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In general, as you can see on the screenshots, the technique is similar, except that not one whole picture is added, but a composite screen. We should do everything in a similar way: add colors, set different palettes to them depending on the theme, and with the pictures we act as in the example above.&lt;/p&gt;

&lt;p&gt;The greatest difficulty of this approach is scaling for different iPhone models. This can be solved with different indentations. They can be static - used equally on all models. Conventionally, 30px on the left - and this will be the case on all models, regardless of whether the screen is smaller or larger. There may also be dynamic indents, as, for example, in the case of a logo. Everything is configured in the View settings (for the image):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5d2amd7mgprlze6d5va4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5d2amd7mgprlze6d5va4.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As well as the location for the screens of different models. It would probably be even more correct to say the indentation that is preserved:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsak6lpd3lxfcc8dqowja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsak6lpd3lxfcc8dqowja.png" alt="Image description" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a word, if you choose this method, you will have to play around with it yourself.&lt;/p&gt;

&lt;p&gt;The final touch is to go to the AppDelegate.m file and add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[super application:application didFinishLaunchingWithOptions:launchOptions];


  [RNSplashScreen show]; // call our SplashScreen


  return YES;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of a line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return [super application:application didFinishLaunchingWithOptions:launchOptions];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add import&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#import "RNSplashScreen.h"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Android setup
&lt;/h2&gt;

&lt;p&gt;We've sorted out iOS, now let's start setting up Android. Here, as well we’ll start with a simple option, when we just use a picture.&lt;/p&gt;

&lt;p&gt;First of all, transfer the generated materials to the res &lt;em&gt;folder (android &amp;gt; app &amp;gt; src &amp;gt; main &amp;gt; res)&lt;/em&gt;. It should come out like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2j9fwg14ing97jw2fjeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2j9fwg14ing97jw2fjeo.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, go to the &lt;em&gt;res &amp;gt; values&lt;/em&gt; folder and create a theme.xml file, insert the following there&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;resources&amp;gt;
  &amp;lt;attr name="launchImage" format="reference"/&amp;gt;
&amp;lt;/resources&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have added a custom &lt;em&gt;launchImage&lt;/em&gt; attribute.&lt;br&gt;
Next, go to the styles.xml file &lt;em&gt;(android/app/src/main/res/values/styles.xml)&lt;/em&gt; and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&amp;gt;
    &amp;lt;resources&amp;gt;

      &amp;lt;style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"&amp;gt;
        ....
      &amp;lt;/style&amp;gt;

      &amp;lt;!-- Add this --&amp;gt;
      &amp;lt;style name="LightTheme" parent="AppTheme"&amp;gt;
        &amp;lt;item name="launchImage"&amp;gt;@drawable/launch_screen_light&amp;lt;/item&amp;gt;
      &amp;lt;/style&amp;gt;

      &amp;lt;!-- Add this --&amp;gt;
      &amp;lt;style name="DarkTheme" parent="AppTheme"&amp;gt;
        &amp;lt;item name="launchImage"&amp;gt;@drawable/launch_screen_dark&amp;lt;/item&amp;gt;
      &amp;lt;/style&amp;gt;

    &amp;lt;/resources&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we added two themes, Light Theme and Dark Theme, and wrote down the values that predetermine our &lt;em&gt;launchImage&lt;/em&gt; image.&lt;/p&gt;

&lt;p&gt;Then in our res folder we create a &lt;em&gt;layout&lt;/em&gt; folder and add the &lt;em&gt;launch_screen.xml&lt;/em&gt; file to it. In this file we write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
    &amp;lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" 
        android:layout_width="match_parent"
        android:layout_height="match_parent"&amp;gt;
        &amp;lt;ImageView 
            android:layout_width="match_parent" 
            android:layout_height="match_parent"
            android:src="?attr/launchImage"
            android:scaleType="centerCrop" 
        /&amp;gt;
    &amp;lt;/RelativeLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we define a link to our image attribute. Pay attention to &lt;em&gt;android:scaleType="fitXY"&lt;/em&gt;. This value may not suit you, you can look for available options &lt;a href="https://developer.android.com/reference/android/widget/ImageView.ScaleType" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally we go to &lt;em&gt;MainActivity.java (android &amp;gt; app &amp;gt; src &amp;gt; main &amp;gt; java &amp;gt; com &amp;gt; packageName &amp;gt; appName &amp;gt; MainActivity.java)&lt;/em&gt; and overwrite the onCreate method with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
protected void onCreate(Bundle savedInstanceState) {
switch (getResources().getConfiguration().uiMode &amp;amp; Configuration.UI_MODE_NIGHT_MASK) {
case Configuration.UI_MODE_NIGHT_YES:
setTheme(R.style.DarkTheme);


break;
case Configuration.UI_MODE_NIGHT_NO:
setTheme(R.style.LightTheme);
break;
default:
setTheme(R.style.LightTheme);
}


SplashScreen.show(this);
super.onCreate(savedInstanceState);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the super.onCreate() method we pass null if the react-native-screens package is used.&lt;/p&gt;

&lt;p&gt;Also at the very top you need to add two imports&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import org.devio.rn.splashscreen.SplashScreen;
import android.content.res.Configuration;


public class MainActivity extends ReactActivity { …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Library implementation
&lt;/h2&gt;

&lt;p&gt;Now all the preparations are completed. All that remains is to implement the library in our application&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App.tsx&lt;/strong&gt;&lt;br&gt;
// import the library&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import SplashScreen from 'react-native-splash-screen' 

export default function App {

    useEffect() {
    // any asynchronous code can be here 
    // before opening the application

    // hide our Splash Screen
        SplashScreen.hide();
    }

    . . . render function

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All that remains is to do yarn run &lt;em&gt;ios / yarn&lt;/em&gt; run android and make sure that everything works well.&lt;/p&gt;

&lt;p&gt;That's all. Our guide on implementing Splash Screen for different themes in react-native is complete. We hope it helps you, and remember that the Splash Screen is a pretty important part of the application, since it is the first thing the user sees. So don't treat it with disdain. Best wishes! The dev.family team was in touch, see you soon!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>ios</category>
      <category>android</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Admiral. Roles and access division in the menu</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 05 Oct 2023 13:51:49 +0000</pubDate>
      <link>https://dev.to/dev_family/admiral-roles-and-access-division-in-the-menu-5gen</link>
      <guid>https://dev.to/dev_family/admiral-roles-and-access-division-in-the-menu-5gen</guid>
      <description>&lt;p&gt;Hi everyone, just a reminder that we are developing Admiral - an open source solution on React, which allows you to quickly develop beautiful CRUDs in admin panels, but create fully custom interfaces if you want. From developers for developers with love, as the saying goes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhy9voeuq8dgna703g7d6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhy9voeuq8dgna703g7d6.png" alt="admiral interface" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our project is available here - &lt;a href="https://github.com/dev-family/admiral" rel="noopener noreferrer"&gt;https://github.com/dev-family/admiral&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today we want to share small tricks on how to create a menu in the control panel that will be generated depending on the user's role. This is quite a popular use case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhu6rxa28tsmub7fejsn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhu6rxa28tsmub7fejsn5.png" alt="alerts" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Menu
&lt;/h3&gt;

&lt;p&gt;From the &lt;a href="https://github.com/dev-family/admiral#menu" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; you can see that out of the box comes an example of building a static menu. Nothing unusual - a menu component with Item (menu items) and SubItem (menu sub-items) with a title, a link to go to and an icon inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Menu, SubMenu, MenuItemLink } from '../../admiral'

const CustomMenu = () =&amp;gt; {
    return (
        &amp;lt;Menu&amp;gt;
            &amp;lt;MenuItemLink icon="FiCircle" name="First Menu Item" to="/first" /&amp;gt;
            &amp;lt;SubMenu icon="FiCircle" name="Second Menu Item"&amp;gt;
                &amp;lt;MenuItemLink icon="FiCircle" name="Sub Menu Item" to="/second" /&amp;gt;
            &amp;lt;/SubMenu&amp;gt;
        &amp;lt;/Menu&amp;gt;
    )
}

export default CustomMenu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if we want to manage this menu? Separate the menu by role? Make it available to guests? That's where creating a Dynamic Menu can help.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic Menu
&lt;/h3&gt;

&lt;p&gt;In order to convert the menu from static to dynamic, we have to get it from somewhere. Let's turn to the documentation, more precisely to &lt;a href="https://github.com/dev-family/admiral#interaction-with-api" rel="noopener noreferrer"&gt;the section on interacting with API&lt;/a&gt;. Let's use the &lt;strong&gt;getIdentity&lt;/strong&gt; method, which gives information about the authorized user, in this case each user will receive the menu available for him along with information about him. Let's go to the file &lt;a href="https://github.com/dev-family/admiral/blob/master/src/config/menu.tsx" rel="noopener noreferrer"&gt;menu.tsx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's first define the basic structure of the menu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface ISubMenuItemChildren {  
    name: string  
    to: string  
    badge?: number  
    icon?: keyof typeof Icons  
}  

interface ISubMenuItem {  
    to?: string  
    name: string  
    badge?: number  
    icon?: keyof typeof Icons  
    children?: Array&amp;lt;ISubMenuItemChildren&amp;gt;  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fields from the name are self-explanatory, but let's break it down just in case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name - name of the menu item&lt;/li&gt;
&lt;li&gt;to - jump link&lt;/li&gt;
&lt;li&gt;badge - optional field that will display a number (total number of records in the menu item, it depends on what number you want to display).&lt;/li&gt;
&lt;li&gt;icon - &lt;a href="https://github.com/dev-family/admiral#icons" rel="noopener noreferrer"&gt;icon&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;children - array with sub-items&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, we plan to get such data using the &lt;strong&gt;getIdentity&lt;/strong&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: "Dev Family",
user: {id: 4, name: "Dev Family", email: "info@dev.family",…},
email: "info@dev.family",
id: 4,
menu: [
    {name: "Users", icon: "FiUsers", badge: null, to: "/users"},
    {name: "Channels", icon: "FiPlayCircle", badge: null, to: "/channels"}
],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's try to parse the array of menu objects in the &lt;strong&gt;menu.tsx&lt;/strong&gt; file, the resulting file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useCallback, useEffect, useState } from 'react'  
import { Menu, MenuItemLink, SubMenu, useGetIdentity } from '@devfamily/admiral'  
import * as Icons from 'react-icons/fi'  

interface ISubMenuItemChildren {  
    name: string  
    to: string  
    badge?: number  
    icon?: keyof typeof Icons  
}  

interface ISubMenuItem {  
    to?: string  
    name: string  
    badge?: number  
    icon?: keyof typeof Icons  
    children?: Array&amp;lt;ISubMenuItemChildren&amp;gt;  
}  

type SubMenuItemsType = Array&amp;lt;ISubMenuItem&amp;gt;  

const CustomMenu = () =&amp;gt; {  
    const { identity } = useGetIdentity()  
    const [filteredSubMenuItems, setFilteredSubMenuItems] = useState&amp;lt;SubMenuItemsType&amp;gt;([])  

    useEffect(() =&amp;gt; {  
        if (identity?.menu &amp;amp;&amp;amp; Array.isArray(identity?.menu)) {  
            setFilteredSubMenuItems(identity?.menu)  
        }  
    }, [identity?.menu])  

    const renderSubMenuItems = useCallback(  
        function () {  
            return (  
                &amp;lt;&amp;gt;  
                    {filteredSubMenuItems.map(function (submenu, i) {  
                        if (submenu.to) {  
                            return (  
                                &amp;lt;MenuItemLink  
                                    key={`${i}`}  
                                    icon={submenu.icon}  
                                    name={submenu.name}  
                                    to={submenu.to}  
                                    badge={{ count: submenu.badge, status: 'error' }}  
                                /&amp;gt;  
                            )  
                        }  

                        if (submenu.children) {  
                            return (  
                                &amp;lt;SubMenu  
                                    key={i}  
                                    icon={submenu.icon}  
                                    name={submenu.name}  
                                    badge={{ count: submenu.badge, status: 'error' }}  
                                &amp;gt;  
                                    {submenu.children.map(function (contentItem, j) {  
                                        return (  
                                            &amp;lt;MenuItemLink  
                                                badge={{ count: contentItem.badge, status: 'warning' }}  
                                                key={`${i}_${j}`}  
                                                icon={contentItem.icon}  
                                                name={contentItem.name}  
                                                to={contentItem.to}  
                                            /&amp;gt;  
                                        )  
                                    })}  
                                &amp;lt;/SubMenu&amp;gt;  
                            )  
                        }  
                    })}  
                &amp;lt;/&amp;gt;  
            )  
        },  
        [filteredSubMenuItems],  
    )  


    return &amp;lt;Menu&amp;gt;{renderSubMenuItems()}&amp;lt;/Menu&amp;gt;  
}  

export default CustomMenu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our menu is fetched from the API method getIdentity and generated dynamically. If you have other use cases we can break down for you, share ideas in the comments!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tgadbvff551p9pv285z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tgadbvff551p9pv285z.png" alt="dev.family team" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>How to get svg from the site</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Tue, 22 Aug 2023 12:20:16 +0000</pubDate>
      <link>https://dev.to/dev_family/how-to-get-svg-from-the-site-5edg</link>
      <guid>https://dev.to/dev_family/how-to-get-svg-from-the-site-5edg</guid>
      <description>&lt;p&gt;If you see the use tag inside the svg - it means that the picture is used by reference, i.e. it is rendered once in the house and then in all other places it is used by reference, how to pull it out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Open the DOM tree&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F247hpy9fkloj6hbuz3yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F247hpy9fkloj6hbuz3yw.png" alt="DOM tree" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Find the link that uses the image&lt;/strong&gt; (in our case &lt;code&gt;xlink:href="#svg-icon-logo"&lt;/code&gt;) &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmyragdqzc3bvc1xk9oa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmyragdqzc3bvc1xk9oa.png" alt="svg-icon-logo" width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Press ctrl+f and paste&lt;/strong&gt; this &lt;code&gt;#svg-icon-logo&lt;/code&gt; ID into it&lt;br&gt;
&lt;strong&gt;4. Find the symbol tag&lt;/strong&gt; with the same id, expand it and see the part of our svg&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1h4jguzmicig56fh3jvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1h4jguzmicig56fh3jvm.png" alt="guts of our svg" width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Copy this element&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgs3bkqvulh4poxxboy6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgs3bkqvulh4poxxboy6.png" alt="copy" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Create a file&lt;/strong&gt; with the extension .svg, open it with Notebook&lt;br&gt;
&lt;strong&gt;7. Take a standard svg tag&lt;/strong&gt; from any other svg&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmm0o58744zme0pi9h1zq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmm0o58744zme0pi9h1zq.png" alt="standard svg tag" width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Plug in the data&lt;/strong&gt; from symbol, replace the properties &lt;code&gt;width="16" height="17" viewBox="0 0 16 17"&lt;/code&gt; in the svg tag with those specified in symbol, in our case it is &lt;code&gt;viewBox="0 0 0 465 146"&lt;/code&gt;, the last two digits are width and height.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Get svg&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhi2h9v6h8a3vf26gp8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhi2h9v6h8a3vf26gp8v.png" alt="get svg" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Be sure to check&lt;/strong&gt; that all quotation marks in tags are not inverse, but regular &lt;code&gt;""&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjznivvy0pt3819tenkq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjznivvy0pt3819tenkq5.png" alt="fin" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>design</category>
      <category>frontend</category>
    </item>
    <item>
      <title>😲😲 Creation of CRUD in 5 minutes</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 17 Aug 2023 09:24:26 +0000</pubDate>
      <link>https://dev.to/dev_family/creation-of-crud-in-5-minutes-ela</link>
      <guid>https://dev.to/dev_family/creation-of-crud-in-5-minutes-ela</guid>
      <description>&lt;p&gt;Where to start... Not too long ago we released our Open Source solution for creating back office on React -  &lt;a href="https://github.com/dev-family/admiral" rel="noopener noreferrer"&gt;https://github.com/dev-family/admiral&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It provides out-of-the-box components and tools that make developing an admin interface easy and fast.&lt;/p&gt;

&lt;p&gt;The reasons we made it were huge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We wanted a solution that quickly creates CRUDs (create, read, update, delete) and requires minimal effort. &lt;/li&gt;
&lt;li&gt;We wanted to be able to create some complex interface if the task required it.&lt;/li&gt;
&lt;li&gt;We make cool, beautiful projects, so we wanted a visually pleasing solution. &lt;/li&gt;
&lt;li&gt;We wanted the solution to be language-independent on the back-end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, we wanted fast, beautiful and custom. And we got it. To prove our words, we decided to show, how you can create CRUD in 5 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's begin
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Express.js&lt;/code&gt; is a modular framework for &lt;code&gt;Node.js&lt;/code&gt; that is used to build web servers and handle HTTP requests. It is great for a quick CRUD startup on Admiral.&lt;/p&gt;

&lt;p&gt;This article consists of 2 parts – creating Backend Admin API and creating entities on the Admiral side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run the command &lt;code&gt;git pull https://github.com/dev-family/admiral.git&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to the &lt;code&gt;/examples/express-server folder&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Follow the installation instructions in the &lt;code&gt;Readme.md&lt;/code&gt; file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3deat5oi2t1bp3961uzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3deat5oi2t1bp3961uzy.png" alt="admiral express server example app" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Express JS Admin API
&lt;/h2&gt;

&lt;p&gt;Now we need to implement the Front part of our application. To do this, you should perform the following actions&lt;/p&gt;

&lt;p&gt;1) Go to the folder &lt;code&gt;/examples/express-server/admin/src/crud&lt;/code&gt;&lt;br&gt;
2) Create the brands folder, in which we create the &lt;code&gt;index.ts&lt;/code&gt; file with the following contents&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createCRUD, SlugInput, TextInput } from 'admiral'
import React from 'react'

export const CRUD = createCRUD({
    path: '/brands',
    resource: 'brands',
    index: {
        title: 'Brands',
        newButtonText: 'Add',
        tableColumns: [
            {
                title: 'ID',
                dataIndex: 'id',
                key: 'id',
                width: 90,
            },
            {
                title: 'Name',
                dataIndex: 'name',
                key: 'name',
            },
            {
                title: 'Slug',
                dataIndex: 'slug',
                key: 'slug',
            },
            {
                title: 'Description',
                dataIndex: 'description',
                key: 'description',
            }
        ],
    },
    form: {
        create: {
            fields: (
                &amp;lt;&amp;gt;
                    &amp;lt;TextInput label="Name" name="name" placeholder="Name" required /&amp;gt;
                    &amp;lt;SlugInput from="name" label="Slug" name="slug" placeholder="Slug" required /&amp;gt;
                    &amp;lt;TextInput label="Description" name="description" placeholder="Description" required /&amp;gt;
                &amp;lt;/&amp;gt;
            ),
        },
        edit: {
            fields: (
                &amp;lt;&amp;gt;
                    &amp;lt;TextInput label="Name" name="name" placeholder="Name" required /&amp;gt;
                    &amp;lt;SlugInput from="name" label="Slug" name="slug" placeholder="Slug" required /&amp;gt;
                    &amp;lt;TextInput label="Description" name="description" placeholder="Description" required /&amp;gt;
                &amp;lt;/&amp;gt;
            ),
        },
    },
    filter: {
        topToolbarButtonText: 'Filters',
        fields: (
            &amp;lt;&amp;gt;
                &amp;lt;TextInput label="Name" name="name" placeholder="Name" /&amp;gt;
            &amp;lt;/&amp;gt;
        ),
    },
    create: {
        title: 'Create Brand',
    },
    update: {
        title: (id: string) =&amp;gt; `Edit Brand #${id}`,
    },
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's talk a little bit more about the CRUD object itself. As you can see, we use various Input components to build CRUD. The full list of components can be found here - &lt;a href="https://admiral.dev.family/components/" rel="noopener noreferrer"&gt;https://admiral.dev.family/components/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;3) Now create a folder in &lt;code&gt;/examples/express-server/admin/pages&lt;/code&gt; (pages - a folder with all pages) with the files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create.tsx (for entity creation mode)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CRUD } from '@/src/crud/brands'

export default CRUD.CreatePage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;[id].tsx (for entity update mode)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CRUD } from '@/src/crud/brands'

export default CRUD.UpdatePage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;index.tsx (for entity list view)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CRUD } from '@/src/crud/brands'

export default CRUD.IndexPage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4) Open our menu file - &lt;code&gt;/examples/express-server/admin/src/config/menu.tsx&lt;/code&gt; and add a new menu item to go to the Brands entity.&lt;/p&gt;

&lt;p&gt;5) Go to our panel, usually &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt; and we should see the following result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjs5ygv6egwesrt14nnnu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjs5ygv6egwesrt14nnnu.png" alt="admiral crud creation" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6) Let's create a test entity&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2mj2893fhmdllop2k4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2mj2893fhmdllop2k4n.png" alt="admiral entity creation" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;7) Result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss7hq4o7m9w7azxz69ph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss7hq4o7m9w7azxz69ph.png" alt="admiral crud" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>programming</category>
      <category>react</category>
      <category>api</category>
    </item>
  </channel>
</rss>
