Using PicoCMS with TailwindCSS and AlpineJS

PicoCMS is a great flat file CMS that is easy to use and extend. This template is a quick way to get started with PicoCMS using TailwindCSS and AlpineJS.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
    <title>{% if meta.title %}{{ meta.title }} | {% endif %}{{ site_title }}</title>
    {% if meta.description %}
        <meta name="description" content="{{ meta.description|striptags }}" />
    {% endif %}
    {% if meta.robots %}
        <meta name="robots" content="{{ meta.robots }}" />
    {% endif %}
    {% if current_page %}
        <link rel="canonical" href="{{ current_page.url }}" />
    {% endif %}
    <script src="//unpkg.com/alpinejs" defer></script>
    <script src="https://cdn.tailwindcss.com/?plugins"></script>
    <style type="text/tailwindcss">
    @layer base {
        #main h1 {
            @apply text-pink-600 text-3xl font-bold pb-4;
        }
        #main h2 {
            @apply text-xl font-bold pb-4;
        }
        #main a {
            @apply underline decoration-pink-600;
        }
        #main p {
            @apply pb-4;
        }
        pre {
            @apply border-s-8 ps-2 text-sm mb-4; 
        }
        ol {
            @apply list-decimal ms-4 pb-4;
        }
        ul {
            @apply list-disc ms-4 pb-4;
        }
    }
    </style>
    <!-- Google tag (gtag.js) -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-J3JXW609KJ"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', 'G-J3JXW609KJ');
    </script>
</head>
<body x-data="{lockScroll:false}" @set-lock.window="lockScroll = !lockScroll" :class="{'overflow-y-hidden':lockScroll}">
    <div id="header" class="container mx-auto max-w-screen-lg pb-4" role="banner" x-data="{ offcanvas: false }">
        <nav class="flex justify-between items-center">
            <span class="text-pink-600 font-bold text-6xl p-1">
                <a href="https://www.blle.co">{{ site_title }}</a>
            </span>
            <button id="hamburger-button" class="p-4 border rounded me-1" @click="offcanvas = true;$dispatch('set-lock')">
                <span class="block w-6 h-1 bg-gray-700"></span>
                <span class="block w-6 h-1 mt-1 bg-gray-700"></span>
                <span class="block w-6 h-1 mt-1 bg-gray-700"></span>
            </button>
        </nav>
        <div id="sideBar" class="fixed top-0 left-0 bg-slate-900/75 h-full w-full overflow-hidden z-10" x-show.important="offcanvas" x-transition.opacity style="display:none">
            <div id="sideNav" class="fixed top-0 right-0 w-full sm:w-[500px] bg-gradient-to-r from-pink-600 to-purple-600 text-black h-full flex justify-center items-center overflow-x-hidden font-bold z-50" @click.away="offcanvas = false;$dispatch('set-lock')" x-show="offcanvas">
                <span class="text-4xl absolute top-0 right-0 mr-3 mt-2 cursor-pointer" @click="offcanvas = false;$dispatch('set-lock')">&times;</span>
                <ul class="text-2xl sm:text-3xl">
                    {% for page in pages(depthOffset=-1,depth=2) if page.title and not page.hidden %}
                        <li class="p-2">
                            <a href="{{ page.url }}">{{ page.title }}</a>
                        </li>
                    {% endfor %}
                </ul>
            </div>
        </div>
    </div>
    <div id="main" role="main">
        {% if meta.banner %}
            <div class="container mx-auto max-w-screen-lg p-1 pb-3">
            <img src="{{ assets_url }}/{{ meta.banner  }}" class="object-cover h-80 w-full rounded"/>
            </div>
        {% endif %}
        <div class="container mx-auto max-w-screen-lg p-1">
            {{ content }}
        </div>
    </div>
    <div id="meta" class="clear-both">
        {% if next_page %}
        <div class="container mx-auto max-w-screen-lg p-1 pt-2">
            <span>Next Page:</span> <a href="{{ next_page.url }}" class="text-pink-600">{{ next_page.title }}</a>
        </div>
        {% else %}
        <div class="container mx-auto max-w-screen-lg p-1 pt-2">
            <span>Next Page:</span> <a href="{{ base_url }}" class="text-pink-600">Home Page</a>
        </div>
        {% endif %}
    </div>
    <div class="container mx-auto max-w-screen-lg pt-4">
        <hr/>
    </div>
        {% if pages('featured')|length  > 0 %}
        <div id="featured" class="">
                <div class="container mx-auto max-w-screen-lg p-1">
                        <h2 class="pt-4 font-bold">Featured Articles:</h2>
                        <div class="flex gap-4">
                                {% for page in pages('featured') if page.title and not page.hidden %}
                                        <div class="w-full sm:w-1/2 lg:w-1/3">
                                                <a class="text-pink-600" href="{{ page.url }}">{{ page.title }}</a>
                                        </div>
                                {% endfor %}
                        </div>
                </div>
        </div>
        {% endif %}
    <div id="footer">
        <div class="container mx-auto max-w-screen-lg pt-4 p-1 text-center">
            <p>Please <a href="https://blle.co" class="underline decoration-pink-600">contact us</a> with any questions or comments. We would love to hear from you!</p>
        </div>
        <div class="container mx-auto max-w-screen-lg p-1 pb-4">
            <div class="social">
                {% for social in pages["_meta"].meta.social %}
                    <a href="{{ social.url }}" title="{{ social.title }}" role="button">
                        <span class="icon-{{ social.icon }}" aria-hidden="true"></span>
                        <span class="sr-only">{{ social.title }}</span>
                    </a>
                {% endfor %}
            </div>
            <p class="text-slate-400 text-center text-sm">
                &copy; 2010 - {{ "now"|date("Y") }} Template by Blue Leaf LLC.
            </p>
        </div>
    </div>
</body>
</html>
Next Article: Puerto Vallarta Condo
Featured Articles
Deploying CakePHP to Fly.io using Docker
A quick guide on how to create your Docker file for CakePHP when using Fly.io for deployment
Using Tailwind with CakePHP
A quick guide for setting up Tailwind CSS with CakePHP
Deploying Flowise to Fly.io
A quick guide on how to deploy a Flowise server to the Fly.io network
Creating a static HTML template for Tailwind and Alpine JS
A guide for creating a basic HTML template that uses Tailwind for styling and Alpine JS for interactive elements