Files
monotab/_site/2024-01-15-getting-started-with-tableau/index.html

247 lines
24 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http_equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
Getting Started with Tableau: Building Static Sites with Elixir | Llmex Blog
</title>
<link rel="stylesheet" href="/css/mono.css">
<meta name="description" content="A comprehensive guide to getting started with Tableau static site generator for Elixir developers.">
</head>
<body class="mono-all">
<header>
<nav class="main-nav">
<div class="logo-container">
<h1><a href="/">Llmex Blog</a></h1>
<button id="mobile-menu-toggle" class="mobile-menu-toggle">
<span class="menu-icon"></span>
</button>
</div>
<ul id="nav-links" class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="/posts">Posts</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<div class="content-wrapper">
<main>
<h1><a inert href="#getting-started-with-tableau-building-static-sites-with-elixir" aria-hidden="true" class="anchor" id="getting-started-with-tableau-building-static-sites-with-elixir"></a>Getting Started with Tableau: Building Static Sites with Elixir</h1>
<p>Static site generators have revolutionized how we build and deploy websites, offering the perfect balance of performance, security, and developer experience. Today, we're exploring <strong>Tableau</strong>, a powerful static site generator built specifically for the Elixir ecosystem.</p>
<h2><a inert href="#why-tableau" aria-hidden="true" class="anchor" id="why-tableau"></a>Why Tableau?</h2>
<p>Tableau brings the elegance and power of Elixir to static site generation. Unlike traditional generators written in Ruby or JavaScript, Tableau leverages:</p>
<ul>
<li><strong>Functional Programming Paradigms</strong> - Immutable data structures and pure functions</li>
<li><strong>Phoenix LiveView Components</strong> - Reusable, testable UI components</li>
<li><strong>HEEx Templates</strong> - HTML-aware templates with compile-time checking</li>
<li><strong>Pattern Matching</strong> - Elegant data transformation and routing</li>
</ul>
<h2><a inert href="#setting-up-your-first-tableau-site" aria-hidden="true" class="anchor" id="setting-up-your-first-tableau-site"></a>Setting Up Your First Tableau Site</h2>
<p>Getting started with Tableau is straightforward. First, add it to your <code>mix.exs</code> dependencies:</p>
<pre class="athl" style="color: #e0e2ea; background-color: #14161b;"><code class="language-elixir" translate="no" tabindex="0"><span class="line" data-line="1"><span style="color: #e0e2ea; font-weight: bold;">defp</span> <span style="color: #8cf8f7;">deps</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="2"> <span style="color: #e0e2ea;">[</span>
</span><span class="line" data-line="3"> <span style="color: #e0e2ea;">&lbrace;</span><span style="color: #8cf8f7;">:tableau</span><span style="color: #e0e2ea;">,</span> <span style="color: #b3f6c0;">&quot;~&gt; 0.25&quot;</span><span style="color: #e0e2ea;">&rbrace;</span><span style="color: #e0e2ea;">,</span>
</span><span class="line" data-line="4"> <span style="color: #e0e2ea;">&lbrace;</span><span style="color: #8cf8f7;">:phoenix_live_view</span><span style="color: #e0e2ea;">,</span> <span style="color: #b3f6c0;">&quot;~&gt; 1.0&quot;</span><span style="color: #e0e2ea;">&rbrace;</span>
</span><span class="line" data-line="5"> <span style="color: #e0e2ea;">]</span>
</span><span class="line" data-line="6"><span style="color: #e0e2ea; font-weight: bold;">end</span>
</span></code></pre>
<p>Then create your first layout:</p>
<pre class="athl" style="color: #e0e2ea; background-color: #14161b;"><code class="language-elixir" translate="no" tabindex="0"><span class="line" data-line="1"><span style="color: #e0e2ea; font-weight: bold;">defmodule</span> <span style="color: #e0e2ea;">MyBlog.RootLayout</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="2"> <span style="color: #e0e2ea; font-weight: bold;">use</span> <span style="color: #e0e2ea;">Tableau.Layout</span>
</span><span class="line" data-line="3"> <span style="color: #e0e2ea; font-weight: bold;">use</span> <span style="color: #e0e2ea;">Phoenix.Component</span>
</span><span class="line" data-line="4">
</span><span class="line" data-line="5"> <span style="color: #e0e2ea; font-weight: bold;">def</span> <span style="color: #8cf8f7;">template</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">assigns</span><span style="color: #e0e2ea;">)</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="6"> <span style="color: #8cf8f7;">~</span>H&quot;&quot;&quot;
</span><span class="line" data-line="7"> <span style="color: #e0e2ea;"><span style="color: #8cf8f7;">&lt;!</span>DOCTYPE html<span style="color: #8cf8f7;">&gt;</span></span>
</span><span class="line" data-line="8"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">html</span> <span style="color: #8cf8f7;">lang</span><span style="color: #e0e2ea;">=</span><span style="color: #b3f6c0;">&quot;<span style="color: #b3f6c0;">en</span>&quot;</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="9"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">head</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="10"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">meta</span> <span style="color: #8cf8f7;">charset</span><span style="color: #e0e2ea;">=</span><span style="color: #b3f6c0;">&quot;<span style="color: #b3f6c0;">utf-8</span>&quot;</span> <span style="color: #8cf8f7;">/&gt;</span>
</span><span class="line" data-line="11"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">title</span><span style="color: #8cf8f7;">&gt;</span><span style="color: #8cf8f7;">&lt;%=</span> <span style="color: #e0e2ea;"><span style="color: #e0e2ea;">@<span style="color: #e0e2ea;">page</span></span></span><span style="color: #e0e2ea;">[</span><span style="color: #8cf8f7;">:title</span><span style="color: #e0e2ea;">]</span><span style="color: #8cf8f7;"> %&gt;</span><span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">title</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="12"> <span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">head</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="13"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">body</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="14"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">main</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="15"> <span style="color: #8cf8f7;">&lt;%=</span> <span style="color: #8cf8f7;">render</span> <span style="color: #e0e2ea;"><span style="color: #e0e2ea;">@<span style="color: #e0e2ea;">inner_content</span></span></span><span style="color: #8cf8f7;"> %&gt;</span>
</span><span class="line" data-line="16"> <span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">main</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="17"> <span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">body</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="18"> <span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">html</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="19"> &quot;&quot;&quot;
</span><span class="line" data-line="20"> <span style="color: #e0e2ea;">|&gt;</span> <span style="color: #e0e2ea;">Phoenix.HTML.Safe</span><span style="color: #e0e2ea;">.</span><span style="color: #8cf8f7;">to_iodata</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">)</span>
</span><span class="line" data-line="21"> <span style="color: #e0e2ea; font-weight: bold;">end</span>
</span><span class="line" data-line="22"><span style="color: #e0e2ea; font-weight: bold;">end</span>
</span></code></pre>
<h2><a inert href="#creating-pages-and-posts" aria-hidden="true" class="anchor" id="creating-pages-and-posts"></a>Creating Pages and Posts</h2>
<p>Tableau makes it easy to create both static pages and blog posts. Pages are defined as Elixir modules:</p>
<pre class="athl" style="color: #e0e2ea; background-color: #14161b;"><code class="language-elixir" translate="no" tabindex="0"><span class="line" data-line="1"><span style="color: #e0e2ea; font-weight: bold;">defmodule</span> <span style="color: #e0e2ea;">MyBlog.Pages.Index</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="2"> <span style="color: #e0e2ea; font-weight: bold;">use</span> <span style="color: #e0e2ea;">Tableau.Page</span><span style="color: #e0e2ea;">,</span>
</span><span class="line" data-line="3"> <span style="color: #8cf8f7;">layout: </span><span style="color: #e0e2ea;">MyBlog.RootLayout</span><span style="color: #e0e2ea;">,</span>
</span><span class="line" data-line="4"> <span style="color: #8cf8f7;">permalink: </span><span style="color: #b3f6c0;">&quot;/&quot;</span>
</span><span class="line" data-line="5">
</span><span class="line" data-line="6"> <span style="color: #e0e2ea; font-weight: bold;">def</span> <span style="color: #8cf8f7;">template</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">assigns</span><span style="color: #e0e2ea;">)</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="7"> <span style="color: #8cf8f7;">~</span>H&quot;&quot;&quot;
</span><span class="line" data-line="8"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">h1</span><span style="color: #8cf8f7;">&gt;</span>Welcome to My Blog<span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">h1</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="9"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">p</span><span style="color: #8cf8f7;">&gt;</span>Built with Elixir and Tableau!<span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">p</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="10"> &quot;&quot;&quot;
</span><span class="line" data-line="11"> <span style="color: #e0e2ea; font-weight: bold;">end</span>
</span><span class="line" data-line="12"><span style="color: #e0e2ea; font-weight: bold;">end</span>
</span></code></pre>
<p>Posts can be written in Markdown with frontmatter, just like other static site generators:</p>
<pre class="athl" style="color: #e0e2ea; background-color: #14161b;"><code class="language-markdown" translate="no" tabindex="0"><span class="line" data-line="1"><span style="color: #8cf8f7;"><span style="color: #e0e2ea; font-weight: bold;">---</span></span>
</span><span class="line" data-line="2"><span style="color: #8cf8f7;"><span style="color: #a6dbff;">title</span><span style="color: #e0e2ea;">:</span> <span style="color: #b3f6c0;">&quot;My First Post&quot;</span></span>
</span><span class="line" data-line="3"><span style="color: #8cf8f7;"><span style="color: #a6dbff;">date</span><span style="color: #e0e2ea;">:</span> <span style="color: #b3f6c0;">&quot;2024-01-15&quot;</span></span>
</span><span class="line" data-line="4"><span style="color: #8cf8f7;"><span style="color: #a6dbff;">layout</span><span style="color: #e0e2ea;">:</span> <span style="color: #b3f6c0;">MyBlog.PostLayout</span></span>
</span><span class="line" data-line="5"><span style="color: #8cf8f7;"><span style="color: #8cf8f7;">---</span></span>
</span><span class="line" data-line="6"><span style="color: #8cf8f7;"></span>
</span><span class="line" data-line="7"><span style="color: #e0e2ea; font-weight: bold;"># Hello, World!</span>
</span><span class="line" data-line="8"><span style="color: #e0e2ea; font-weight: bold;"></span>
</span><span class="line" data-line="9">This is my first blog post using Tableau.
</span></code></pre>
<h2><a inert href="#advanced-features" aria-hidden="true" class="anchor" id="advanced-features"></a>Advanced Features</h2>
<h3><a inert href="#component-reusability" aria-hidden="true" class="anchor" id="component-reusability"></a>Component Reusability</h3>
<p>One of Tableau's strongest features is its integration with Phoenix LiveView components. You can create reusable components and use them across your site:</p>
<pre class="athl" style="color: #e0e2ea; background-color: #14161b;"><code class="language-elixir" translate="no" tabindex="0"><span class="line" data-line="1"><span style="color: #e0e2ea; font-weight: bold;">defmodule</span> <span style="color: #e0e2ea;">MyBlog.Components.PostCard</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="2"> <span style="color: #e0e2ea; font-weight: bold;">use</span> <span style="color: #e0e2ea;">Phoenix.Component</span>
</span><span class="line" data-line="3">
</span><span class="line" data-line="4"> <span style="color: #8cf8f7;">attr</span> <span style="color: #8cf8f7;">:post</span><span style="color: #e0e2ea;">,</span> <span style="color: #8cf8f7;">:map</span><span style="color: #e0e2ea;">,</span> <span style="color: #8cf8f7;">required: </span><span style="color: #e0e2ea;">true</span>
</span><span class="line" data-line="5">
</span><span class="line" data-line="6"> <span style="color: #e0e2ea; font-weight: bold;">def</span> <span style="color: #8cf8f7;">post_card</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">assigns</span><span style="color: #e0e2ea;">)</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="7"> <span style="color: #8cf8f7;">~</span>H&quot;&quot;&quot;
</span><span class="line" data-line="8"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">article</span> <span style="color: #8cf8f7;">class</span><span style="color: #e0e2ea;">=</span><span style="color: #b3f6c0;">&quot;<span style="color: #b3f6c0;">post-card</span>&quot;</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="9"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">h2</span><span style="color: #8cf8f7;">&gt;</span><span style="color: #8cf8f7;">&lt;%=</span> <span style="color: #e0e2ea;"><span style="color: #e0e2ea;">@<span style="color: #e0e2ea;">post</span></span></span><span style="color: #e0e2ea;">.</span><span style="color: #e0e2ea;">title</span><span style="color: #8cf8f7;"> %&gt;</span><span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">h2</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="10"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">time</span><span style="color: #8cf8f7;">&gt;</span><span style="color: #8cf8f7;">&lt;%=</span> <span style="color: #e0e2ea;"><span style="color: #e0e2ea;">@<span style="color: #e0e2ea;">post</span></span></span><span style="color: #e0e2ea;">.</span><span style="color: #e0e2ea;">date</span><span style="color: #8cf8f7;"> %&gt;</span><span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">time</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="11"> <span style="color: #8cf8f7;">&lt;</span><span style="color: #8cf8f7;">p</span><span style="color: #8cf8f7;">&gt;</span><span style="color: #8cf8f7;">&lt;%=</span> <span style="color: #e0e2ea;"><span style="color: #e0e2ea;">@<span style="color: #e0e2ea;">post</span></span></span><span style="color: #e0e2ea;">.</span><span style="color: #e0e2ea;">excerpt</span><span style="color: #8cf8f7;"> %&gt;</span><span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">p</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="12"> <span style="color: #8cf8f7;">&lt;/</span><span style="color: #8cf8f7;">article</span><span style="color: #8cf8f7;">&gt;</span>
</span><span class="line" data-line="13"> &quot;&quot;&quot;
</span><span class="line" data-line="14"> <span style="color: #e0e2ea; font-weight: bold;">end</span>
</span><span class="line" data-line="15"><span style="color: #e0e2ea; font-weight: bold;">end</span>
</span></code></pre>
<h3><a inert href="#data-processing" aria-hidden="true" class="anchor" id="data-processing"></a>Data Processing</h3>
<p>Leverage Elixir's powerful data processing capabilities to transform and filter your content:</p>
<pre class="athl" style="color: #e0e2ea; background-color: #14161b;"><code class="language-elixir" translate="no" tabindex="0"><span class="line" data-line="1"><span style="color: #e0e2ea; font-weight: bold;">defmodule</span> <span style="color: #e0e2ea;">MyBlog.Posts</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="2"> <span style="color: #e0e2ea; font-weight: bold;">def</span> <span style="color: #8cf8f7;">recent_posts</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">posts</span><span style="color: #e0e2ea;">,</span> <span style="color: #e0e2ea;">limit</span> <span style="color: #e0e2ea;">\\</span> <span style="color: #e0e2ea;">5</span><span style="color: #e0e2ea;">)</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="3"> <span style="color: #e0e2ea;">posts</span>
</span><span class="line" data-line="4"> <span style="color: #e0e2ea;">|&gt;</span> <span style="color: #e0e2ea;">Enum</span><span style="color: #e0e2ea;">.</span><span style="color: #8cf8f7;">sort_by</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">&amp;</span> <span style="color: #e0e2ea;">&amp;</span><span style="color: #e0e2ea;">1</span><span style="color: #e0e2ea;">.</span><span style="color: #e0e2ea;">date</span><span style="color: #e0e2ea;">,</span> <span style="color: #e0e2ea;">&lbrace;</span><span style="color: #8cf8f7;">:desc</span><span style="color: #e0e2ea;">,</span> <span style="color: #e0e2ea;">Date</span><span style="color: #e0e2ea;">&rbrace;</span><span style="color: #e0e2ea;">)</span>
</span><span class="line" data-line="5"> <span style="color: #e0e2ea;">|&gt;</span> <span style="color: #e0e2ea;">Enum</span><span style="color: #e0e2ea;">.</span><span style="color: #8cf8f7;">take</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">limit</span><span style="color: #e0e2ea;">)</span>
</span><span class="line" data-line="6"> <span style="color: #e0e2ea; font-weight: bold;">end</span>
</span><span class="line" data-line="7">
</span><span class="line" data-line="8"> <span style="color: #e0e2ea; font-weight: bold;">def</span> <span style="color: #8cf8f7;">posts_by_tag</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">posts</span><span style="color: #e0e2ea;">,</span> <span style="color: #e0e2ea;">tag</span><span style="color: #e0e2ea;">)</span> <span style="color: #e0e2ea; font-weight: bold;">do</span>
</span><span class="line" data-line="9"> <span style="color: #e0e2ea;">Enum</span><span style="color: #e0e2ea;">.</span><span style="color: #8cf8f7;">filter</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">posts</span><span style="color: #e0e2ea;">,</span> <span style="color: #e0e2ea;">&amp;</span><span style="color: #e0e2ea;">(</span><span style="color: #e0e2ea;">tag</span> <span style="color: #e0e2ea; font-weight: bold;">in</span> <span style="color: #e0e2ea;">&amp;</span><span style="color: #e0e2ea;">1</span><span style="color: #e0e2ea;">.</span><span style="color: #e0e2ea;">tags</span><span style="color: #e0e2ea;">)</span><span style="color: #e0e2ea;">)</span>
</span><span class="line" data-line="10"> <span style="color: #e0e2ea; font-weight: bold;">end</span>
</span><span class="line" data-line="11"><span style="color: #e0e2ea; font-weight: bold;">end</span>
</span></code></pre>
<h2><a inert href="#performance-and-seo" aria-hidden="true" class="anchor" id="performance-and-seo"></a>Performance and SEO</h2>
<p>Tableau generates fully static HTML, which means:</p>
<ul>
<li><strong>Lightning-fast load times</strong> - No server-side processing required</li>
<li><strong>Excellent SEO</strong> - Search engines can easily crawl static HTML</li>
<li><strong>CDN-friendly</strong> - Deploy anywhere static files are supported</li>
<li><strong>Security</strong> - No server-side vulnerabilities</li>
</ul>
<h2><a inert href="#deployment" aria-hidden="true" class="anchor" id="deployment"></a>Deployment</h2>
<p>Building your site is as simple as running:</p>
<pre class="athl" style="color: #e0e2ea; background-color: #14161b;"><code class="language-bash" translate="no" tabindex="0"><span class="line" data-line="1"><span style="color: #8cf8f7;">mix</span> <span style="color: #e0e2ea;">tableau.build</span>
</span></code></pre>
<p>The generated site will be in the <code>_site</code> directory, ready to deploy to any static hosting service like Netlify, Vercel, or GitHub Pages.</p>
<h2><a inert href="#conclusion" aria-hidden="true" class="anchor" id="conclusion"></a>Conclusion</h2>
<p>Tableau brings the power and elegance of Elixir to static site generation. With its integration with Phoenix LiveView, powerful templating system, and functional programming paradigms, it's an excellent choice for developers who want to build fast, maintainable static sites.</p>
<p>Whether you're building a personal blog, documentation site, or marketing pages, Tableau provides the tools and flexibility you need while maintaining the reliability and performance that static sites are known for.</p>
<p>Ready to get started? Check out the <a href="https://hexdocs.pm/tableau">official Tableau documentation</a> and start building your next static site with Elixir!</p>
<time datetime="2024-01-15T00:00:00Z"></time>
</main>
<aside class="sidebar">
<div class="sidebar-content">
<h3>Recent Posts</h3>
<ul class="sidebar-posts">
<li><a href="/posts/2024-01-15-getting-started-with-tableau">Getting Started with Tableau</a></li>
<li><a href="/posts/2024-01-10-functional-programming-benefits">The Benefits of Functional Programming</a></li>
</ul>
<h3>Categories</h3>
<ul class="sidebar-categories">
<li><a href="/posts/elixir">Elixir</a></li>
<li><a href="/posts/phoenix">Phoenix</a></li>
<li><a href="/posts/functional-programming">Functional Programming</a></li>
</ul>
</div>
</aside>
</div>
<footer>
<p>&copy; 2025 Llmex Blog. Built with Elixir & Tableau.</p>
<div class="mobile-nav">
<a href="/">Home</a>
<a href="/posts">Posts</a>
<a href="/about">About</a>
</div>
</footer>
<script>
document.getElementById('mobile-menu-toggle').addEventListener('click', function() {
document.getElementById('nav-links').classList.toggle('active');
this.classList.toggle('active');
});
</script>
</body>
<script>
function log(message) {
if (true) {
console.log(`[web_dev_utils] ${message}`)
}
}
function connect() {
try {
window.socket = new WebSocket('ws://' + location.host + '/ws');
window.socket.onmessage = function(e) {
if (e.data === "reload") {
log("reloading!");
location.reload();
} else if (e.data === "subscribed") {
log("connected and subscribed!");
}
}
window.socket.onopen = () => {
waitForConnection(() => {
log("sending 'subscribe' message");
window.socket.send("subscribe")
}
, 300);
};
window.socket.onclose = () => {
setTimeout(() => connect(), 500);
};
function waitForConnection(callback, interval) {
log("waiting for connection!")
if (window.socket.readyState === 1) {
callback();
} else {
log("setting a timeout")
setTimeout(() => waitForConnection(callback, interval), interval);
}
}
} catch (e) {
log(e);
setTimeout(() => connect(), 500);
}
}
log("about to connect");
connect();
</script>
</html>