<?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: It's Just Nifty</title>
    <description>The latest articles on DEV Community by It's Just Nifty (@nifty-little-me).</description>
    <link>https://dev.to/nifty-little-me</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%2Fuser%2Fprofile_image%2F2077997%2Fc87bb6e4-a029-4460-83e0-07019c16ee20.png</url>
      <title>DEV Community: It's Just Nifty</title>
      <link>https://dev.to/nifty-little-me</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nifty-little-me"/>
    <language>en</language>
    <item>
      <title>Creating Extensions In Opera For Beginners</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Wed, 25 Sep 2024 23:27:47 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/creating-extensions-in-opera-for-beginners-5hg5</link>
      <guid>https://dev.to/nifty-little-me/creating-extensions-in-opera-for-beginners-5hg5</guid>
      <description>&lt;p&gt;Opera is my favorite browser! I mean, I'm using it right now. If you don't know, now you know. Besides being awesome, &lt;a href="https://www.opera.com" rel="noopener noreferrer"&gt;Opera&lt;/a&gt; makes it easy to create extensions...which is pretty awesome. So, why not share this easy guide on how to do it? This is gonna be quick, so let's dive in!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimagedelivery.net%2FlLmNeOP7HXG0OqaG97wimw%2Fclxihdzyt0000fs3t08d6dwio%2Fe0d55c3e-8c72-452b-9318-88b391134a11.jpg%2Fpublic" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimagedelivery.net%2FlLmNeOP7HXG0OqaG97wimw%2Fclxihdzyt0000fs3t08d6dwio%2Fe0d55c3e-8c72-452b-9318-88b391134a11.jpg%2Fpublic" alt="Unsplash Image From Luca Bravo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://unsplash.com/photos/turned-on-gray-laptop-computer-XJXWbfSo2f0" rel="noopener noreferrer"&gt;Image Source&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Create your project directory, and then a &lt;code&gt;manifest.json&lt;/code&gt; file by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code -r manifest.json 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BTW, &lt;code&gt;code -r manifest.json&lt;/code&gt; is used in VSCode (&lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt;). Let's continue!&lt;/p&gt;

&lt;p&gt;Add this code to your &lt;code&gt;manifest.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "manifest_version": 2,
    "name": "First Opera Extension",
    "description": "example extension",
    "version": "1.0",
    "browser_action": {
        "default_popup": "index.html",
        "default_icon": "icon.png",
        "default_title": "My first extension"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Excellent!&lt;/p&gt;

&lt;p&gt;Now, create a &lt;code&gt;index.html&lt;/code&gt; file and add code, similar to 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;!DOCTYPE html&amp;gt;
&amp;lt;html style="width: 357px; height: 300px; border: 1px solid #e7e9eb; border-radius: 10px;"&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you grab an icon from somewhere, or you can create one. Either way, add an icon for your extension and title it &lt;code&gt;icon.png&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;In Opera, type into the browser's address bar &lt;code&gt;opera://extensions&lt;/code&gt; or use the shortcut &lt;code&gt;cmd/ctrl + shift + E&lt;/code&gt;. Then enable developer mode. You should see a switch...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimagedelivery.net%2FlLmNeOP7HXG0OqaG97wimw%2Fclxihdzyt0000fs3t08d6dwio%2Fc181cd08-749b-488b-8431-296af029142c.png%2Fpublic" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimagedelivery.net%2FlLmNeOP7HXG0OqaG97wimw%2Fclxihdzyt0000fs3t08d6dwio%2Fc181cd08-749b-488b-8431-296af029142c.png%2Fpublic" alt="Showing where developer mode switch is in opera | screenshot snippet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on "Load Unpacked Extension" and select the folder of your project.&lt;/p&gt;

&lt;p&gt;And then...you're done.&lt;/p&gt;

&lt;p&gt;Congrats on your extension.&lt;/p&gt;

&lt;p&gt;If you like me, and I know you do, subscribe to my newsletter!&lt;/p&gt;

&lt;p&gt;Until next time, nerds...&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

&lt;p&gt;Love ya ❤️&lt;/p&gt;

</description>
      <category>learntocode</category>
      <category>html</category>
      <category>coding</category>
      <category>programming</category>
    </item>
    <item>
      <title>Creating Dynamic Routes With Metadata in Next.Js</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Mon, 16 Sep 2024 02:50:57 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/creating-dynamic-routes-with-metadata-in-nextjs-2i1k</link>
      <guid>https://dev.to/nifty-little-me/creating-dynamic-routes-with-metadata-in-nextjs-2i1k</guid>
      <description>&lt;p&gt;&lt;strong&gt;This is for the app router&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I learned a lot while creating my own blog website. One of the things I learned that stuck in my head was how to create dynamic routes with metadata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.niftylittleme.com" rel="noopener noreferrer"&gt;Nifty Little Me&lt;/a&gt; was not a walk in the park. Those dynamic routes was a pain. And after I figured that out, I had to fight the magic dragon, aka metadata.&lt;/p&gt;

&lt;p&gt;I gained a nifty little blog and something to write about.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.niftylittleme.com/articles/creating-dynamic-routes-in-the-nextjs-app-router-and-adding-metadata" rel="noopener noreferrer"&gt;Learn how to create dynamic routes with metadata for Next.js app router!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>learning</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Downloading Webpages As PDFs With PHP And JavaScript</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Sun, 15 Sep 2024 22:16:48 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/downloading-webpages-as-pdfs-with-php-and-javascript-56hh</link>
      <guid>https://dev.to/nifty-little-me/downloading-webpages-as-pdfs-with-php-and-javascript-56hh</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_2RcNzxH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/2595cbbb-ba31-4287-a26a-3c2376b70195.png/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_2RcNzxH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/2595cbbb-ba31-4287-a26a-3c2376b70195.png/public" alt="The results - Cropped Screenshot" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.niftylittleme.com/articles/converting-html-to-pdf-with-html-button" rel="noopener noreferrer"&gt;Converting HTML to a PDF in PHP was easy.&lt;/a&gt; Let's bring it up a notch and convert a webpage to a PDF file using PHP and JavaScript.&lt;/p&gt;

&lt;p&gt;To do this, you will need to install &lt;a href="https://getcomposer.org/doc/00-intro.md" rel="noopener noreferrer"&gt;Composer&lt;/a&gt; and &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After installing those things, you will need to install &lt;a href="https://github.com/dompdf/dompdf" rel="noopener noreferrer"&gt;Dompdf&lt;/a&gt; using Composer and &lt;a href="https://pptr.dev" rel="noopener noreferrer"&gt;Puppeteer&lt;/a&gt; using &lt;a href="https://www.npmjs.com" rel="noopener noreferrer"&gt;npm&lt;/a&gt; (Node package manager):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require dompdf/dompdf

npm install puppeteer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a HTML file (Example: index.html):&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;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Webpage to Pdf&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;main&amp;gt;
        &amp;lt;form action="web-pdf.php" method="get"&amp;gt;
            &amp;lt;label for="url"&amp;gt;Website URL:&amp;lt;/label&amp;gt;
            &amp;lt;input type="text" id="url" name="url" required&amp;gt;
            &amp;lt;button type="submit"&amp;gt;Download Content&amp;lt;/button&amp;gt;
        &amp;lt;/form&amp;gt;
    &amp;lt;/main&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a PHP file (Example: web-pdf.php):&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;?php
require 'vendor/autoload.php';

use Dompdf\Dompdf;

if (isset($_GET['url'])) {
    $url = escapeshellarg($_GET['url']);
    $content = shell_exec("node download.js {$url}");

    try {
        convertHTML($content);
    } catch (Exception $e) {
        echo "Some error: " . $e-&amp;gt;getMessage();
    }
} else {
    echo "No URL provided.";
}

function convertHTML($content) {
    $dompdf = new Dompdf();
    $dompdf-&amp;gt;loadHtml($content);

    // Setup the paper size and orientation
    $dompdf-&amp;gt;setPaper('A4', 'landscape');

    // Render the HTML as PDF
    $dompdf-&amp;gt;render();

    ob_end_clean();

    // Output the generated PDF
    $dompdf-&amp;gt;stream();
}
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, create a JavaScript File to use Puppeteer (Example: download.js):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const puppeteer = require('puppeteer');

// Get URL from command-line arguments
const url = process.argv[2];

(async () =&amp;gt; {
  try {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url); // Use the URL passed from PHP
    await page.waitForSelector('main', { timeout: 10000 }); // Adjust selector and timeout as needed

    const content = await page.content();
    console.log(content);

    await browser.close();
  } catch (error) {
    console.error('Error:', error);
  }
})();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note: Remove the ten second timeout or change the element (main) if the content is not what you expect.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There you go! Just like that, you have a webpage to PDF converter.&lt;/p&gt;

&lt;p&gt;Happy Coding Folks!&lt;/p&gt;

</description>
      <category>html</category>
      <category>javascript</category>
      <category>npm</category>
      <category>php</category>
    </item>
    <item>
      <title>Converting HTML To PDF With HTML Button</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Sun, 15 Sep 2024 19:24:59 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/converting-html-to-pdf-with-html-button-4dg7</link>
      <guid>https://dev.to/nifty-little-me/converting-html-to-pdf-with-html-button-4dg7</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimagedelivery.net%2FlLmNeOP7HXG0OqaG97wimw%2Fclxihdzyt0000fs3t08d6dwio%2F8c28dde9-97b5-4538-854f-91cd495352d5.png%2Fpublic" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimagedelivery.net%2FlLmNeOP7HXG0OqaG97wimw%2Fclxihdzyt0000fs3t08d6dwio%2F8c28dde9-97b5-4538-854f-91cd495352d5.png%2Fpublic" alt="Converting HTML to PDF Part 3 - Original Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.niftylittleme.com/articles/how-to-convert-html-to-pdf-with-php" rel="noopener noreferrer"&gt;It's easy to convert HTML into a PDF with the help of libraries.&lt;/a&gt; Sometimes starting a download once you've navigated to a page is needed; however, let's give people the option to download the PDF or not. You can do that by adding HTML to your converter. Here's how.&lt;/p&gt;

&lt;p&gt;HTML code (Example: index.php):&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;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Html to Pdf&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;?php
        $content = '&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;';
        echo $content;
    ?&amp;gt;
    &amp;lt;main&amp;gt;
        &amp;lt;a href='html-php.php?download=true&amp;amp;content=&amp;lt;?php echo addslashes($content); ?&amp;gt;'&amp;gt;Create PDF&amp;lt;/a&amp;gt;
    &amp;lt;/main&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PHP code (Example: html-php.php):&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;?php
    require 'vendor/autoload.php';

    // reference the Dompdf namespace
    use Dompdf\Dompdf;


    if (isset($_GET['download'])) {
        $content = $_GET['content'];
        try {
            convertHTML($content);
        } catch ( Exception $e) {
            echo "some error:" . $e-&amp;gt;getMessage();
        }
    }

    function convertHTML($content){

        // instantiate and use the dompdf class
        $dompdf = new Dompdf();
        $dompdf-&amp;gt;loadHtml($content);

        // (Optional) Setup the paper size and orientation
        $dompdf-&amp;gt;setPaper('A4', 'landscape');

        // Render the HTML as PDF
        $dompdf-&amp;gt;render();

        ob_end_clean();

        // Output the generated PDF to Browser
        $dompdf-&amp;gt;stream();
    }
    ?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>php</category>
      <category>programming</category>
      <category>html</category>
      <category>pdffiles</category>
    </item>
    <item>
      <title>How To Convert HTML To PDF With PHP</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Sun, 15 Sep 2024 02:30:00 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/how-to-convert-html-to-pdf-with-php-4eb5</link>
      <guid>https://dev.to/nifty-little-me/how-to-convert-html-to-pdf-with-php-4eb5</guid>
      <description>&lt;p&gt;&lt;em&gt;(Guide For Windows. Not Mac or Linux)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jrvoHePV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/a20aa786-b335-4d99-b4ee-a1babf2cf7de.jpg/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jrvoHePV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/a20aa786-b335-4d99-b4ee-a1babf2cf7de.jpg/public" alt="Unsplash Image by Christopher Gower" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://unsplash.com/photos/a-macbook-with-lines-of-code-on-its-screen-on-a-busy-desk-m_HRfLhgABo" rel="noopener noreferrer"&gt;(Image Source)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's more than one way to convert HTML to a PDF in PHP. You can use Dompdf or Mpdf; however, there is a difference in how these two libraries are doing it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Not all solutions will be in this article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To use both these libraries, you will need &lt;a href="https://getcomposer.org/doc/00-intro.md#installation-windows" rel="noopener noreferrer"&gt;Composer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Converting HTML To PDF With Dompdf
&lt;/h2&gt;

&lt;p&gt;I also show the code in the &lt;a href="https://www.niftylittleme.com/articles/unable-to-open-dompdf-pdf-file-heres-the-solution" rel="noopener noreferrer"&gt;article discussing why the PDF sometimes won't open when using Dompdf&lt;/a&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;?php
        require 'vendor/autoload.php';

        // reference the Dompdf namespace
        use Dompdf\Dompdf;

        $content = '&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;';

        // instantiate and use the dompdf class
        $dompdf = new Dompdf();
        $dompdf-&amp;gt;loadHtml($content);

        // (Optional) Setup the paper size and orientation
        $dompdf-&amp;gt;setPaper('A4', 'landscape');

        // Render the HTML as PDF
        $dompdf-&amp;gt;render();

        ob_end_clean();

        // Output the generated PDF to Browser
        $dompdf-&amp;gt;stream();
    ?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this code, the PDF is downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Converting HTML To PDF With Mpdf
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
    require_once __DIR__. '/vendor/autoload.php';
    use Mpdf\Mpdf;
    $mpdf = new Mpdf();
    $mpdf-&amp;gt;WriteHTML('&amp;lt;h1&amp;gt;Hello world! Hi&amp;lt;/h1&amp;gt;');
    $mpdf-&amp;gt;Output();
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this code, the PDF is opened in the browser when you navigate to your file &lt;strong&gt;(Example: localhost/test1.php)&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>html</category>
      <category>tutorial</category>
      <category>coding</category>
    </item>
    <item>
      <title>Unable To Open Dompdf PDF File? Here's The Solution</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Sun, 15 Sep 2024 00:03:10 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/unable-to-open-dompdf-pdf-file-heres-the-solution-5d19</link>
      <guid>https://dev.to/nifty-little-me/unable-to-open-dompdf-pdf-file-heres-the-solution-5d19</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JiOooNdu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/d458bf0c-754d-4c19-82a5-e6ff8e53c786.jpg/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JiOooNdu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/d458bf0c-754d-4c19-82a5-e6ff8e53c786.jpg/public" alt="Unsplash Image by Kevin Ku" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://unsplash.com/photos/closeup-photo-of-eyeglasses-w7ZyuGYNpRQ" rel="noopener noreferrer"&gt;(Image Source)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To open a PDF made with Dompdf, you might want to add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ob_end_clean();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$dompdf-&amp;gt;stream();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your PHP project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ob_end_clean — Clean (erase) the contents of the active output buffer and turn it off&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.php.net/manual/en/function.ob-end-clean.php" rel="noopener noreferrer"&gt;&lt;strong&gt;(Quote Source)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full Example Code:&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;?php
        require 'vendor/autoload.php';

        // reference the Dompdf namespace
        use Dompdf\Dompdf;

        $content = '&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;';

        // instantiate and use the dompdf class
        $dompdf = new Dompdf();
        $dompdf-&amp;gt;loadHtml($content);

        // (Optional) Setup the paper size and orientation
        $dompdf-&amp;gt;setPaper('A4', 'landscape');

        // Render the HTML as PDF
        $dompdf-&amp;gt;render();

        ob_end_clean();

        // Output the generated PDF to Browser
        $dompdf-&amp;gt;stream();
    ?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For potentially more answers, go &lt;a href="https://stackoverflow.com/q/20676160/23056177" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>learntocode</category>
      <category>coding</category>
    </item>
    <item>
      <title>How To Use Tailwind CSS With A Plain PHP Project</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Wed, 11 Sep 2024 20:29:23 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/how-to-use-tailwind-css-with-a-plain-php-project-170a</link>
      <guid>https://dev.to/nifty-little-me/how-to-use-tailwind-css-with-a-plain-php-project-170a</guid>
      <description>&lt;p&gt;&lt;a href="https://unsplash.com/photos/macbook-pro-beside-white-ceramic-mug-on-brown-wooden-table-k-rKfqSm4L4?utm_content=creditShareLink&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;(Image Source)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pe872_2x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/696d2195-8014-4070-804b-670af516079d.jpg/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pe872_2x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/696d2195-8014-4070-804b-670af516079d.jpg/public" alt="Image from Nathan da Silva on Unsplash" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To start using Tailwind CSS with your plain PHP project, you can install Tailwind CSS in your project. This is how:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;npm init -y&lt;/code&gt; in the terminal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install Tailwind dependencies: &lt;code&gt;npm install tailwindcss postcss autoprefixer&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate Tailwind configuration file: &lt;code&gt;npx tailwindcss init&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;postcss.config.js&lt;/code&gt; file and add this code:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
  ],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a folder called &lt;code&gt;src&lt;/code&gt; and a &lt;code&gt;styles.css&lt;/code&gt; file with this code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add a build script to your &lt;code&gt;package.json&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "scripts": {
    "build:css": "npx postcss src/styles.css -o public/styles.css"
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;npm run build:css&lt;/code&gt; in the terminal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Include a link to the &lt;code&gt;public/styles.css&lt;/code&gt; in your page’s file (example: index.php):&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link href="./public/styles.css" rel="stylesheet"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Make sure you run &lt;code&gt;npm run build:css&lt;/code&gt; after making changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also, make sure your &lt;code&gt;tailwind.config.js&lt;/code&gt; includes the paths to your &lt;code&gt;.php&lt;/code&gt; and &lt;code&gt;.html&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/** @type {import('tailwindcss').Config} */
module.exports = {
  darkMode: 'class', // or 'media'
  content: [
    "./**/*.php",
    "./**/*.html"
  ],
  theme: {
    extend: {
...
    }
  },
  plugins: [],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy Coding Folks!&lt;/p&gt;

</description>
      <category>coding</category>
      <category>tailwindcss</category>
      <category>php</category>
      <category>css</category>
    </item>
    <item>
      <title>Creating Reusable HTML Components In PHP</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Mon, 09 Sep 2024 04:34:44 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/creating-reusable-html-components-in-php-3i5j</link>
      <guid>https://dev.to/nifty-little-me/creating-reusable-html-components-in-php-3i5j</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i__F-3Wa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/e390489a-8303-41aa-8c08-f22ecde30ed0.jpg/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i__F-3Wa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/e390489a-8303-41aa-8c08-f22ecde30ed0.jpg/public" alt="Unsplash Image By Ben Griffiths" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://unsplash.com/photos/blue-elephant-figurine-on-macbook-pro-Bj6ENZDMSDY?utm_content=creditShareLink&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;&lt;em&gt;Image Source&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re creating your website with PHP and HTML, you’ll want to reuse some components. For example, instead of creating identical headers for all the pages, you can create one header component and use it on multiple pages. Reusable PHP components will save you time.&lt;/p&gt;

&lt;p&gt;In PHP web development, you can create these php components by creating a new file (example: header.component.php). Creating a folder for the file to go in is optional, but in this article, we will do it anyway (components/header.component.php).&lt;/p&gt;

&lt;p&gt;Inside the header.component.php file, add the code for your header:&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;?php
function createHeader() {
    return '
          &amp;lt;header&amp;gt;
       ...
          &amp;lt;/header&amp;gt;
    ';
  }  
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add this to your page’s code (&lt;strong&gt;Not the component. Example: index.php&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;?php
            include "./components/header.component.php";
            echo createHeader();
        ?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy Coding Folks!&lt;/p&gt;

</description>
      <category>development</category>
      <category>learntocode</category>
      <category>php</category>
      <category>html</category>
    </item>
    <item>
      <title>Whoever Said You Need An IDE To Program In C?</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Fri, 23 Aug 2024 16:56:33 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/whoever-said-you-need-an-ide-to-program-in-c-ddp</link>
      <guid>https://dev.to/nifty-little-me/whoever-said-you-need-an-ide-to-program-in-c-ddp</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note: This guide is for Windows only and the steps might differ for Mac and Linux users&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s face it, IDEs can take up a lot of unnecessary room. So, forget all the noise you heard about using an IDE and just give me a minute of your time. In my life, C has been a language thrown around in semi-crowded rooms. Kinda like that one building you pass all the time on your way somewhere important to you. I never took a second to look into it. Mainly because I thought you needed an IDE or to install more stuff on your already full computer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xgKj0e_i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/f5c64692-47ee-43ba-baaa-bc1d171eef35.png/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xgKj0e_i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/f5c64692-47ee-43ba-baaa-bc1d171eef35.png/public" alt="learning how to program in c - Image made by Nifty Little Me" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I tried C for the first time, I was shocked. No, I didn’t download and install an IDE. I did something else instead. Something that you can do too 🙂. So what did I do? Well, I downloaded GCC, installed the C/C++ extension in VSCode, and started programming. Here are the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to this &lt;a href="https://sourceforge.net/projects/gcc-win64/" rel="noopener noreferrer"&gt;website&lt;/a&gt; to download a GCC zip file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Download the latest version&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extract the zip file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rename the extracted folder (make the name shorter, &lt;strong&gt;ex: gcc-14.1.0&lt;/strong&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move the folder to the &lt;strong&gt;(C:) directory&lt;/strong&gt; in files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside the folder, go to the bin folder&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the path to the bin folder&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to your &lt;strong&gt;environment variables&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on Path in &lt;strong&gt;System Variables&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the path to the GCC bin directory to &lt;strong&gt;Path&lt;/strong&gt; (System Variables)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the CMD ( &lt;strong&gt;Command Prompt&lt;/strong&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;gcc –version&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you have verified GCC, make a folder ( &lt;strong&gt;ex: testing-c&lt;/strong&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the folder in &lt;strong&gt;VSCode&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a C file ( &lt;strong&gt;ex: testing1.c&lt;/strong&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy and Paste this code:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open CMD ( &lt;strong&gt;Command Prompt&lt;/strong&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to your folder in CMD ( &lt;strong&gt;ex: testing-c&lt;/strong&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;gcc testing1.c&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;a&lt;/code&gt; or &lt;code&gt;a.exe&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congrats, you are now on the bus that goes down C road. Have a seat and get ready for the bumps, wrong turns, and potholes. What makes this bus different is we’re going to be getting off at EVERY STOP because there is always a lot to learn on this trip.&lt;/p&gt;

&lt;p&gt;With that being said, I can’t wait to learn C.&lt;/p&gt;

&lt;p&gt;Happy Coding Folks!&lt;/p&gt;

</description>
      <category>ide</category>
      <category>vscode</category>
      <category>windows</category>
      <category>c</category>
    </item>
    <item>
      <title>You Created A React Native Android App? Cool. How Do You Publish It?</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Wed, 21 Aug 2024 18:43:53 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/you-created-a-react-native-android-app-cool-how-do-you-publish-it-5c48</link>
      <guid>https://dev.to/nifty-little-me/you-created-a-react-native-android-app-cool-how-do-you-publish-it-5c48</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: This guide is for Windows only&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, I’ve been creating mobile apps. What have you been doing? Probably the same thing if you clicked on this article. Or maybe you’re just curious; however, I’m going to assume that you have created your React Native Android app already, and are ready to start tackling publishing it to Google Play.&lt;/p&gt;

&lt;p&gt;So, how do you do that? Well, if you’re like younger me and think it’s as easy as the ABCs, you’re wrong. Let me just tell ya, I had one heck of a time trying to do this. But the struggle was worth it because now I get to share the steps. Without further ado, let’s jump right in!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XNo57IH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/a7c524fd-fcc0-4377-a7aa-dd5251b40a3a.jpg/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XNo57IH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/a7c524fd-fcc0-4377-a7aa-dd5251b40a3a.jpg/public" alt="Unsplash Image by Pathum Danthanarayana" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Image Above: Photo by&lt;/em&gt; &lt;a href="https://unsplash.com/@pathum_danthanarayana?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;&lt;em&gt;Pathum Danthanarayana&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on&lt;/em&gt; &lt;a href="https://unsplash.com/photos/turned-on-android-smartphone-t8TOMKe6xZU?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;&lt;em&gt;Unsplash&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating An AAB File
&lt;/h2&gt;

&lt;p&gt;So what is an AAB file? To my understanding, it’s a file the Google Play Store prompts you for when trying to publish an app there. By the way, the AAB file is what Google Play calls the App Bundle.&lt;/p&gt;

&lt;p&gt;Anyway, how do you generate one?&lt;/p&gt;

&lt;p&gt;Well, the first step is creating an upload key keystore. I expect you to have a version of JDK installed because you need it to have a React Native Android app developed in the first place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Have JDK Installed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open CMD (Command Prompt) As Administrator&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate To JDK Bin Directory: &lt;code&gt;C:\Program Files\Java\jdkx.x.x_x\bin&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run this Command: &lt;code&gt;keytool -genkeypair -v -storetype PKCS12 -keystore my-upload-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter Keystore Password When Prompted&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep The Keystore File Private&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Place the Keystore File In Your &lt;code&gt;android/app&lt;/code&gt; Folder&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add This Code To Your &lt;code&gt;android/gradle.properties&lt;/code&gt; file:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add this code to your &lt;code&gt;android/app/build.gradle&lt;/code&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open CMD (Command Prompt) Again&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate To &lt;code&gt;android/app&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run This Command: &lt;code&gt;./gradlew.bat bundleRelease&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And after all of that, you should have an app-release.aab file. Make sure it’s in the &lt;code&gt;android\app\build\outputs\bundle\release&lt;/code&gt; directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inside The Google Play Console
&lt;/h2&gt;

&lt;p&gt;After you did all of that there is more. Go to your Google Play Console, and yes, pay the $25. After you make that little investment, let’s get your Android app out there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create A &lt;strong&gt;New App&lt;/strong&gt; In Your Google Play Console&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt; App By Completing All The Steps Listed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manage&lt;/strong&gt; Your App Listing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When Creating Releases, Upload The AAB File You Have Created For &lt;strong&gt;App Bundles&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go Through With Testing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make Sure You Meet The &lt;a href="https://support.google.com/googleplay/android-developer/answer/14151465#overview" rel="noopener noreferrer"&gt;Requirements&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Additional Steps
&lt;/h2&gt;

&lt;p&gt;You might want to update your app to fix bugs, errors, etc…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Change Version, Version Code, and Version Name In &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;android/app/build.gradle&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open CMD (Command Prompt) Again!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate To &lt;code&gt;android/app&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run This Command: &lt;code&gt;./gradlew.bat bundleRelease&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create A New Release In The Google Play Console&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;And just like that, you are done, your app is published, and everyone is happy. Yay, splendid, and congrats! These are the steps I took, so follow them to a T and you should be fine.&lt;/p&gt;

&lt;p&gt;Check out my other Articles! &lt;a href="https://www.niftylittleme.com/articles/how-to-set-up-firebase-in-your-bare-react-native-project-for-android?blogId=clz05hthr0009ku28hjh4vcim?slug=how-to-set-up-firebase-in-your-bare-react-native-project-for-android" rel="noopener noreferrer"&gt;Learn how to set up Firebase in your React Native project&lt;/a&gt;. To find out what I'm writing next, &lt;a href="https://nifty-little-me.ck.page/c449633aba" rel="noopener noreferrer"&gt;subscribe to my newsletter&lt;/a&gt;. Also, check out my &lt;a href="https://medium.com/@programming-advice" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; if you like me so much.&lt;/p&gt;

&lt;p&gt;Happy Coding Folks!&lt;/p&gt;

</description>
      <category>appdevelopment</category>
      <category>android</category>
      <category>reactnative</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Adding Chat Functionality To Your Next.Js Project With Firebase</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Sun, 18 Aug 2024 23:28:05 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/adding-chat-functionality-to-your-nextjs-project-with-firebase-4h7o</link>
      <guid>https://dev.to/nifty-little-me/adding-chat-functionality-to-your-nextjs-project-with-firebase-4h7o</guid>
      <description>&lt;p&gt;Compared to all the other things you can add to your Next.Js projects, chat functionality has to be one of the easiest things you can implement. Why? Because there are a bunch of solutions out there for good reasons. A lot of websites are popping up with live chat features, more often than not for help, support, and to talk to a representative, which is why it’s important to know how to code a chat feature.&lt;/p&gt;

&lt;p&gt;But, of course, you already know that, right? Why else would you click on this tutorial walking you through how to do it? And you’re probably gonna skip this introduction anyway to get into the nitty-gritty. So, let’s get into coder mode and get started!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--izKCfIuG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/8cf43503-1103-4825-acb6-38b9f18b7255.png/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--izKCfIuG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/8cf43503-1103-4825-acb6-38b9f18b7255.png/public" alt="Original Image" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Learn all about &lt;a href="https://firebase.google.com" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt; on the website. You might fall in love with it. And if you don’t know what &lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;Next.Js&lt;/a&gt; is…seriously, what are you doing here? But you can learn more about this great &lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;React framework in its documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To follow this tutorial, create a Firestore collection called ‘users’ with a name field. Then, create a collection called ‘chats’ with the fields being a timestamp called ‘createdAt’ and an array called ‘participants’. Inside the document, create a collection called ‘messages’ with fields ‘senderId’, ‘text’, and ‘timestamp’.&lt;/p&gt;

&lt;p&gt;You also need to ensure you have a &lt;code&gt;firebase.js&lt;/code&gt; file in the app directory of your project. Inside should be your Firebase config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getAuth } from "firebase/auth";
import { getStorage } from 'firebase/storage';

const firebaseConfig = {
  apiKey: "API_KEY",
  authDomain: "AUTH_DOMIAN",
  projectId: "PROJECT_ID",
  storageBucket: "STORAGE_BUCKET",
  messagingSenderId: "MESSAGE_SENDER_ID",
  appId: "APP_ID"
};

const app = initializeApp(firebaseConfig);

const db = getFirestore(app);

const auth = getAuth(app);

const storage = getStorage(app);

export { db, auth, storage };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we can start on the chat component, we can make life easier by creating a &lt;code&gt;users&lt;/code&gt; file with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { collection, getDocs } from 'firebase/firestore';
import { db } from '@/app/firebase';

interface User {
  id: string;
  name: string;
}

async function fetchUsers(): Promise&amp;lt;User[]&amp;gt; {
  const usersCollection = collection(db, 'users');
  const usersSnapshot = await getDocs(usersCollection);
  const usersList = usersSnapshot.docs.map(doc =&amp;gt; ({ id: doc.id, ...doc.data() } as User));
  return usersList;
}

export {
  fetchUsers
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that setup, let’s get started with the actual chat code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Down The Chat Code
&lt;/h2&gt;

&lt;p&gt;Now, we can create a file in the folder with all the rest of our components (this folder may vary depending on your setup or you might need to create a &lt;code&gt;components&lt;/code&gt; folder in your app directory) and let’s name the file &lt;code&gt;chat.jsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These are the self-explanatory imports you should have:&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 { useEffect, useState, useRef } from 'react';
import { getFirestore, collection, addDoc, Timestamp, query, onSnapshot, orderBy, getDocs } from 'firebase/firestore';
import { useRouter, useSearchParams } from 'next/navigation';
import { fetchUsers } from './users';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to declare quite a bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const searchParams = useSearchParams();
  const router = useRouter();
  const [messages, setMessages] = useState([]);
  const [newMessage, setNewMessage] = useState('');
  const chatContainerRef = useRef(null); // Ref for chat container

  const user1Id = searchParams.get('user1Id'); // Get user1Id from URL parameters
  const user2Id = searchParams.get('user2Id'); // Get user2Id from URL parameters
  const [user1, setUser1] = useState(null);
  const [user2, setUser2] = useState(null);
  const [isReversed, setIsReversed] = useState(false);
  const [currentUserId, setCurrentUserId] = useState(null);
  const [chatId, setChatId] = useState(null);

  const db = getFirestore();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to set the current user id:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  useEffect(() =&amp;gt; {
    const id = searchParams.get('user1Id');
    setCurrentUserId(id);
  }, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let’s create a chat session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const createChatSession = async (participants) =&amp;gt; {
    try {
      const chatDocRef = await addDoc(collection(db, 'chats'), {
        participants,
        createdAt: Timestamp.fromDate(new Date()),
      });
      return chatDocRef.id;
    } catch (error) {
      console.error("Error creating chat session:", error);
      throw error;
    }
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to fetch all of the necessary data, such as the user’s info, and retrieve the chat session if there is one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  useEffect(() =&amp;gt; {
    const fetchData = async () =&amp;gt; {
      const users = await fetchUsers();
      const user1Data = users.find(user =&amp;gt; user.id === user1Id);
      const user2Data = users.find(user =&amp;gt; user.id === user2Id);

      setUser1(user1Data || null);
      setUser2(user2Data || null);

      if (currentUserId === user1Id) {
        setIsReversed(false);
      } else if (currentUserId === user2Id) {
        setIsReversed(true);
      }

      const chatDocRef = collection(db, 'chats');
      const chatQuery = query(chatDocRef, orderBy('createdAt'));
      const chatSnapshot = await getDocs(chatQuery);
      const chatDoc = chatSnapshot.docs.find(doc =&amp;gt; doc.data().participants.includes(user1Id) &amp;amp;&amp;amp; doc.data().participants.includes(user2Id));

      if (chatDoc) {
        setChatId(chatDoc.id);
      } else {
        const newChatId = await createChatSession([user1Id, user2Id]);
        setChatId(newChatId);
      }
    };

    fetchData();
  }, [user1Id, user2Id, currentUserId, db]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also will get the messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  useEffect(() =&amp;gt; {
    if (!chatId) return;
    const q = query(collection(db, `chats/${chatId}/messages`), orderBy('timestamp'));
    const unsubscribe = onSnapshot(q, (snapshot) =&amp;gt; {
      const newMessages = snapshot.docs.map(doc =&amp;gt; doc.data());
      setMessages(newMessages);
    });

    console.log('Messages')

    return () =&amp;gt; unsubscribe();
  }, [chatId, db]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After we get the messages, we need to ensure that the messages appear on the bottom first, and a part of doing that will be thanks to adding this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  useEffect(() =&amp;gt; {
    // Scroll to the bottom of the chat container when new messages are added
    if (chatContainerRef.current) {
      chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
    }
  }, [messages]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handle sending messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const handleSendMessage = async (messageText) =&amp;gt; {
    if (messageText.trim() &amp;amp;&amp;amp; chatId) {
      await addDoc(collection(db, `chats/${chatId}/messages`), {
        senderId: currentUserId,
        text: messageText,
        timestamp: Timestamp.fromDate(new Date()),
      });
      setNewMessage('');
    }
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let’s generate the chat link so the other user can join:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const generateChatLink = () =&amp;gt; {
   const currentUrl = window.location.origin;
   const chatUrl = `${currentUrl}?user1Id=${user2.id}&amp;amp;user2Id=${user1.id}&amp;amp;chatId=${chatId}`;
   return chatUrl;
  };

  const chatLink = generateChatLink();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Display the link:&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;div className='p-4'&amp;gt;
          &amp;lt;p&amp;gt;Share this link with {user2.name} to join the chat:&amp;lt;/p&amp;gt;
          &amp;lt;input type="text" value={chatLink} className="text-black" readOnly style={{ width: '100%', padding: '8px', marginBottom: '10px' }} /&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; navigator.clipboard.writeText(chatLink)} className='bg-blue-500 text-white p-2 rounded'&amp;gt;Copy Link&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the container for the messages:&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;div
          className="chat-container bg-opacity-55 bg-slate-900 m-4 p-4"
          ref={chatContainerRef}
          style={{
            display: 'flex',
            flexDirection: 'column',
            justifyContent: 'flex-end',
            overflowY: 'auto',
            height: 'calc(80vh - 220px)',
            marginTop: '10px',
            border: '1px solid red',
          }}
        &amp;gt;
          {messages.map((message, index) =&amp;gt; (
            &amp;lt;div
              key={index}
              className={`message ${message.senderId === user1.id ? (isReversed ? 'received' : 'sent') : (isReversed ? 'sent' : 'received')}`}
              style={{
                backgroundColor: message.senderId === user1.id
                  ? (isReversed ? 'lightgray' : 'blue')
                  : (isReversed ? 'blue' : 'lightgray'),
                color: message.senderId === user1.id ? 'white' : 'black',
                borderRadius: '10px',
                padding: '10px',
                marginBottom: '10px',
                alignSelf: message.senderId === user1.id ? 'flex-end' : 'flex-start',
                maxWidth: '60%',
              }}
            &amp;gt;
              &amp;lt;div className="bubble text-black"&amp;gt;{message.text}&amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, add a way to type the message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MessageInput = ({ onSendMessage }) =&amp;gt; {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (event) =&amp;gt; {
    setInputValue(event.target.value);
  };

  const handleSend = () =&amp;gt; {
    if (inputValue.trim() !== '') {
      onSendMessage(inputValue);
      setInputValue('');
    }
  };

  return (
    &amp;lt;div className="message-input" style={{ position: 'absolute', bottom: 0, width: '100%', display: 'flex', alignItems: 'center', padding: '10px', backgroundColor: 'rgba(0, 0, 0, 0.5)' }}&amp;gt;
      &amp;lt;input
        type="text"
        value={inputValue}
        onChange={handleChange}
        style={{ flex: 1, marginRight: '10px', padding: '10px', borderRadius: '5px', border: '1px solid #fff', color: '#000' }}
      /&amp;gt;
      &amp;lt;button
        onClick={handleSend}
        style={{ padding: '10px', borderRadius: '5px', backgroundColor: '#007BFF', color: '#fff', border: 'none' }}&amp;gt;
        Send
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s put the pieces together!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full Code
&lt;/h2&gt;

&lt;p&gt;This is the full code:&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 { useEffect, useState, useRef } from 'react';
import { getFirestore, collection, addDoc, Timestamp, query, onSnapshot, orderBy, getDocs } from 'firebase/firestore';
import { useRouter, useSearchParams } from 'next/navigation';
import { fetchUsers } from './users';

const ChatPage = () =&amp;gt; {
  const searchParams = useSearchParams();
  const router = useRouter();
  const [messages, setMessages] = useState([]);
  const [newMessage, setNewMessage] = useState('');
  const chatContainerRef = useRef(null); // Ref for chat container

  const user1Id = searchParams.get('user1Id'); // Get user1Id from URL parameters
  const user2Id = searchParams.get('user2Id'); // Get user2Id from URL parameters
  const [user1, setUser1] = useState(null);
  const [user2, setUser2] = useState(null);
  const [isReversed, setIsReversed] = useState(false);
  const [currentUserId, setCurrentUserId] = useState(null);
  const [chatId, setChatId] = useState(null);

  const db = getFirestore();

  useEffect(() =&amp;gt; {
    // Get the user ID from local storage
    const id = searchParams.get('user1Id');
    setCurrentUserId(id);
  }, []);

  const createChatSession = async (participants) =&amp;gt; {
    try {
      // Add a new chat document to the 'chats' collection
      const chatDocRef = await addDoc(collection(db, 'chats'), {
        participants,
        createdAt: Timestamp.fromDate(new Date()), // Add creation timestamp
      });
      return chatDocRef.id; // Return the new chat document ID
    } catch (error) {
      console.error("Error creating chat session:", error);
      throw error;
    }
  };

  useEffect(() =&amp;gt; {
    const fetchData = async () =&amp;gt; {
      const users = await fetchUsers(); // Fetch all users
      const user1Data = users.find(user =&amp;gt; user.id === user1Id);
      const user2Data = users.find(user =&amp;gt; user.id === user2Id);

      setUser1(user1Data || null);
      setUser2(user2Data || null);

      // Determine user roles
      if (currentUserId === user1Id) {
        setIsReversed(false); // Normal color scheme for user1
      } else if (currentUserId === user2Id) {
        setIsReversed(true); // Reverse colors for user2
      }

      // Create or retrieve chat session
      const chatDocRef = collection(db, 'chats');
      const chatQuery = query(chatDocRef, orderBy('createdAt'));
      const chatSnapshot = await getDocs(chatQuery);
      const chatDoc = chatSnapshot.docs.find(doc =&amp;gt; doc.data().participants.includes(user1Id) &amp;amp;&amp;amp; doc.data().participants.includes(user2Id));

      if (chatDoc) {
        setChatId(chatDoc.id);
      } else {
        const newChatId = await createChatSession([user1Id, user2Id]);
        setChatId(newChatId);
      }

    };

    fetchData();
  }, [user1Id, user2Id, currentUserId, db]);

  useEffect(() =&amp;gt; {
    if (!chatId) return;

    const q = query(collection(db, `chats/${chatId}/messages`), orderBy('timestamp'));
    const unsubscribe = onSnapshot(q, (snapshot) =&amp;gt; {
      const newMessages = snapshot.docs.map(doc =&amp;gt; doc.data());
      setMessages(newMessages);
    });

    console.log('Messages')

    return () =&amp;gt; unsubscribe();
  }, [chatId, db]);

  useEffect(() =&amp;gt; {
    // Scroll to the bottom of the chat container when new messages are added
    if (chatContainerRef.current) {
      chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
    }
  }, [messages]);

  const handleSendMessage = async (messageText) =&amp;gt; {
    if (messageText.trim() &amp;amp;&amp;amp; chatId) {
      await addDoc(collection(db, `chats/${chatId}/messages`), {
        senderId: currentUserId,
        text: messageText,
        timestamp: Timestamp.fromDate(new Date()),
      });
      setNewMessage(''); // Clear the input field
    }
  };

  if (!user1 || !user2 || !chatId) {
    return &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;;
  }

  const generateChatLink = () =&amp;gt; {
   const currentUrl = window.location.origin;
   const chatUrl = `${currentUrl}?user1Id=${user2.id}&amp;amp;user2Id=${user1.id}&amp;amp;chatId=${chatId}`;
   return chatUrl;
  };

  const chatLink = generateChatLink();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div style={{ position: 'relative', zIndex: 1, height: '100vh' }}&amp;gt;
        &amp;lt;h2 className='text-purple-300 text-xl'&amp;gt;Chat with {user2.name}&amp;lt;/h2&amp;gt;

        &amp;lt;div className='p-4'&amp;gt;
          &amp;lt;p&amp;gt;Share this link with {user2.name} to join the chat:&amp;lt;/p&amp;gt;
          &amp;lt;input type="text" value={chatLink} className="text-black" readOnly style={{ width: '100%', padding: '8px', marginBottom: '10px' }} /&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; navigator.clipboard.writeText(chatLink)} className='bg-blue-500 text-white p-2 rounded'&amp;gt;Copy Link&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div
          className="chat-container bg-opacity-55 bg-slate-900 m-4 p-4"
          ref={chatContainerRef}
          style={{
            display: 'flex',
            flexDirection: 'column',
            justifyContent: 'flex-end',
            overflowY: 'auto',
            height: 'calc(80vh - 220px)',
            marginTop: '10px',
            border: '1px solid red',
          }}
        &amp;gt;
          {messages.map((message, index) =&amp;gt; (
            &amp;lt;div
              key={index}
              className={`message ${message.senderId === user1.id ? (isReversed ? 'received' : 'sent') : (isReversed ? 'sent' : 'received')}`}
              style={{
                backgroundColor: message.senderId === user1.id
                  ? (isReversed ? 'lightgray' : 'blue')
                  : (isReversed ? 'blue' : 'lightgray'),
                color: message.senderId === user1.id ? 'white' : 'black',
                borderRadius: '10px',
                padding: '10px',
                marginBottom: '10px',
                alignSelf: message.senderId === user1.id ? 'flex-end' : 'flex-start',
                maxWidth: '60%', // Ensure messages do not stretch too far horizontally
              }}
            &amp;gt;
              &amp;lt;div className="bubble text-black"&amp;gt;{message.text}&amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;

        &amp;lt;MessageInput onSendMessage={handleSendMessage} /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

const MessageInput = ({ onSendMessage }) =&amp;gt; {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (event) =&amp;gt; {
    setInputValue(event.target.value);
  };

  const handleSend = () =&amp;gt; {
    if (inputValue.trim() !== '') {
      onSendMessage(inputValue); // Pass the inputValue to the onSendMessage function
      setInputValue('');
    }
  };

  return (
    &amp;lt;div className="message-input" style={{ position: 'absolute', bottom: 0, width: '100%', display: 'flex', alignItems: 'center', padding: '10px', backgroundColor: 'rgba(0, 0, 0, 0.5)' }}&amp;gt;
      &amp;lt;input
        type="text"
        value={inputValue}
        onChange={handleChange}
        style={{ flex: 1, marginRight: '10px', padding: '10px', borderRadius: '5px', border: '1px solid #fff', color: '#000' }}
      /&amp;gt;
      &amp;lt;button
        onClick={handleSend}
        style={{ padding: '10px', borderRadius: '5px', backgroundColor: '#007BFF', color: '#fff', border: 'none' }}&amp;gt;
        Send
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Modify The Code
&lt;/h2&gt;

&lt;p&gt;The code I provided is not a one-size-fits-all solution. It’s more like a starting point to push you in the right direction.&lt;/p&gt;




&lt;p&gt;You just learned how to code a basic chat page with Firebase and Next.js. That’s one simple thing you can cross off your to-do list. Well, that’s about it for this article.&lt;/p&gt;

&lt;p&gt;Make sure you follow me on &lt;a href="https://medium.com/@programming-advice" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; and &lt;a href="https://nifty-little-me.ck.page/c449633aba" rel="noopener noreferrer"&gt;subscribe to my newsletter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy Coding Folks!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>approuter</category>
      <category>firebase</category>
      <category>react</category>
    </item>
    <item>
      <title>Spicing Up Your Next.Js Projects With 3D: What Are Your Options?</title>
      <dc:creator>It's Just Nifty</dc:creator>
      <pubDate>Sat, 17 Aug 2024 21:44:33 +0000</pubDate>
      <link>https://dev.to/nifty-little-me/spicing-up-your-nextjs-projects-with-3d-what-are-your-options-4b67</link>
      <guid>https://dev.to/nifty-little-me/spicing-up-your-nextjs-projects-with-3d-what-are-your-options-4b67</guid>
      <description>&lt;p&gt;In the past, I have experimented with 3D modeling. My knowledge of how to do it goes as far as downloading the software, so my expertise is merely surface-level. I always knew, based on some websites, that you can incorporate 3D elements into web development, but only recently have I dipped my toe in the water.&lt;/p&gt;

&lt;p&gt;What can you do with 3D? A lot. Even that sounds like an understatement. But if there’s one thing I’m certain of it’s this: adding 3D elements to a website is the easiest way to create a unique browsing experience. I mean, there are better ways to describe the effect 3D elements have. Like, I can say it makes an interactive and immersive experience for your users. But, in my opinion, that means the same thing and also fails to explain the impact a little 3D has. When I showed off a website with 3D elements, mouths dropped and I just knew the bar was going to be higher for my company and me.&lt;/p&gt;

&lt;p&gt;So, how can you add 3D to your Next.js projects? Well, let’s take a look.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--khgvM6aK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/f5bc7d2f-a357-4099-b1cf-474742a6c18b.png/public" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--khgvM6aK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagedelivery.net/lLmNeOP7HXG0OqaG97wimw/clxihdzyt0000fs3t08d6dwio/f5bc7d2f-a357-4099-b1cf-474742a6c18b.png/public" alt="Original Image" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Three.Js In Your Next.Js Project
&lt;/h2&gt;

&lt;p&gt;When I was &lt;a href="https://medium.com/@programming-advice/my-beef-with-remix-why-i-hate-it-9b8e8cd83c41" rel="noopener noreferrer"&gt;experimenting with Remix&lt;/a&gt;, I used &lt;a href="https://threejs.org/docs/index.html#manual/en/introduction/Installation" rel="noopener noreferrer"&gt;Three.js&lt;/a&gt;, and when I realized the learning curve with Remix, I took my 3D creations over to Next.js. I chop my reasoning down to Next.js being easier and more understandable. Sorry Remix, but not sorry. BTW, I secretly hate you and will never use you again. Hope we’re still friends, XX.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm i three&lt;/code&gt; in your project and import &lt;code&gt;import * as THREE from 'three'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After that, the instructions break off into one million strands. It all depends on what you are creating, which is why I was so conflicted about making this article. What I write depends on what I’m working on and I’m working on 3D in web design; however, there’s not a one-size-fits-all guide to what you’re trying to create in 3D.&lt;/p&gt;

&lt;p&gt;I will tell you this much though. Three.js is an excellent choice. My 3D creations turned out wonderful and the complexity level is low for beginners. It’s also one of the popular choices, which means more resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Could Babylon.Js Be Used Instead?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://doc.babylonjs.com/setup/frameworkPackages/es6Support" rel="noopener noreferrer"&gt;Babylon.js&lt;/a&gt; is a neat Three.js alternative; however, resources on how to actually use it with Next.js are pretty limited. Because of the lack of resources, you should lean towards Three.js instead; however, if you like a challenge and desperately need an alternative for some reason give Babylon.js a shot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovering react-three-fiber
&lt;/h2&gt;

&lt;p&gt;This handy dandy library is for using Three.js in React components. I didn’t even know this existed when I was using Three.js, which makes me question &lt;a href="https://github.com/pmndrs/react-three-fiber" rel="noopener noreferrer"&gt;react-three-fiber’s existence&lt;/a&gt;. Is it needed? No, but let’s talk about this library anyway.&lt;/p&gt;

&lt;p&gt;Just like with Three.js, I was shaken by how easy react-three-fiber was. To get started, run &lt;code&gt;npm install three @types/three @react-three/fiber&lt;/code&gt; and then for a basic 3D animation, create a new component in your project and copy this code:&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 { createRoot } from 'react-dom/client'
import React, { useRef, useState } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'

function Box(props) {
  const ref = useRef();
  const [hovered, hover] = useState(false);
  const [clicked, click] = useState(false);
  useFrame((state, delta) =&amp;gt; (ref.current.rotation.x += delta));

  return (
    &amp;lt;mesh
      {...props}
      ref={ref}
      scale={clicked ? 1.5 : 1}
      onClick={(event) =&amp;gt; click(!clicked)}
      onPointerOver={(event) =&amp;gt; hover(true)}
      onPointerOut={(event) =&amp;gt; hover(false)}&amp;gt;
      &amp;lt;boxGeometry args={[1, 1, 1]} /&amp;gt;
      &amp;lt;meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} /&amp;gt;
    &amp;lt;/mesh&amp;gt;
  )
}

export default function MainComponent () {
    return (
        &amp;lt;div&amp;gt;
        &amp;lt;Canvas&amp;gt;
            &amp;lt;ambientLight intensity={Math.PI / 2} /&amp;gt;
            &amp;lt;spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} decay={0} intensity={Math.PI} /&amp;gt;
            &amp;lt;pointLight position={[-10, -10, -10]} decay={0} intensity={Math.PI} /&amp;gt;
            &amp;lt;Box position={[-1.2, 0, 0]} /&amp;gt;
            &amp;lt;Box position={[1.2, 0, 0]} /&amp;gt;
        &amp;lt;/Canvas&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Looking Into Drei
&lt;/h2&gt;

&lt;p&gt;No doubt that I’m not the only one who has never heard of &lt;a href="https://github.com/pmndrs/drei" rel="noopener noreferrer"&gt;Drei&lt;/a&gt; before. I figure that a lot of you haven’t as well. Basically, Drei is a collection of useful helpers for react-three-fiber. If you are interested, check out the &lt;a href="https://github.com/pmndrs/drei" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;With all that being said and checked off the list, the article is coming to a close. Thank you for reading…or skimming. I hope you got something out of this and you can start adding 3D elements to your next.js projects.&lt;/p&gt;

&lt;p&gt;Happy Coding Folks!&lt;/p&gt;

</description>
      <category>webdesign</category>
      <category>approuter</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
  </channel>
</rss>
