Saaze / saaze

An all-inclusive, flat-file CMS for simple websites and blogs.
https://saaze.dev
MIT License
48 stars 6 forks source link

Provide repository for themes and plugins #3

Open eklausme opened 3 years ago

eklausme commented 3 years ago

As Saaze can be extended quite easily, it is expected that more extensions and template-themes will emerge. We should collect them "somewhere", so people can find them easily.

I created an extension for Saaze modeled after the documentation as given in Extending. This extension provides:

  1. MathJax support for inline and display math, i.e., single dollar and double dollar notation, taking into account to not spoil with math within code-blocks
  2. Embedding YouTube videos like so: [youtube] shortcode [/youtube]
  3. Embedding Tweets from Twitter like so: [twitter] Tweet URL [/twitter]

File definitions.php is:

<?php

require_once 'MathParser.php';

return [
    \Saaze\Interfaces\ContentParserInterface::class => \MathParser::class,
];

File MathParser.php is:

<?php

use Saaze\Content\MarkdownContentParser;

class MathParser extends MarkdownContentParser {
        /**
         * Work on abc $$uvw$$ xyz.
         * Needs MathJax. For this you have to include:
         *    <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
         *    <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
         *
         * @param string $content
         * @return string
         */
        private function displayMath($content) {
                $last = 0;
                for (;;) {
                        $start = strpos($content,"$$",$last);
                        if ($start === false) break;
                        $end = strpos($content,"$$",$start+2);
                        if ($end === false) break;
                        $last = $end + 2;
                        $content = substr($content,0,$start)
                                . "\n<div class=math>\n"
                                . substr($content,$start,$last-$start)
                                . "\n</div>\n"
                                . substr($content,$last);
                        $last += strlen("\n<div class=math>\n") + strlen("\n</div>\n");
                }
                return $content;
        }

        /**
         * Work on abc $uvw$ xyz.
         * @param string $content
         * @return string
         */
        private function inlineMath($content) {
                $last = 0;
        for (;;) {
            $start = strpos($content,"$",$last);
            if ($start === false) break;
            // Check if display math with double dollar found?
            if (substr($content,$start+1,1) == "$") { $last = $start + 2; continue; }
            $end = strpos($content,"$",$start+1);
            if ($end === false) break;
            // Check for display math again, just in case
            if (substr($content,$end+1,1) == "$") { $last = $end + 2; continue; }
            // Replace $xyz$" with \\(xyz\\)
            $content = substr_replace($content,"\\\\(",$start,1);
            $content = substr_replace($content,"\\\\)",$end+2,1);
            $last = $end + 5;   // effectivley added four chars
        }
                return $content;
        }

        /**
         * Convert [youtube]xxx[/youtube] tags in your markdown to HTML:
         * <iframe width="560" height="315" src=https://www.youtube.com/embed/xxx
         *    frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
         * Example: [youtube] a5pnnkXpX-U     [/youtube]
         *
         * @param string $content
         * @return string
         */
        private function youtube($content) {
                $last = 0;
                for (;;) {
                        $start = strpos($content,"[youtube]",$last);
                        if ($start === false) break;
                        // strlen("[youtube]") == 9
                        $end = strpos($content,"[/youtube]",$start+9);
                        if ($end === false) break;
                        $video = trim(substr($content,$start+9,$end-$start-9));
                        $last = $end + 10;
                        $content = substr_replace($content
                                ,"<iframe width=560 height=315 src=https://www.youtube.com/embed/"
                                . $video
                                . " frameborder=0 allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>"
                                ,$start,$last-$start);
                }
                return $content;
        }

        /**
         * Convert [twitter]xxx[/twitter] tags in your markdown HTML which Twitter-JavaScript understands.
         * xxx is for example: https://twitter.com/eklausmeier/status/1352896936051937281
         * i.e., just the URL, no other information is required.
         * This xxx is "Copy link to Tweet" button in Twitter.
         *
         * Make sure that your layout-template contains the following:
         *    <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
         *
         * @param string $content
         * @return string
         */
        private function twitter($content) {
                $last = 0;
                for (;;) {
                        $start = strpos($content,"[twitter]",$last);
                        if ($start === false) break;
                        // strlen("[twitter]") == 9
                        $end = strpos($content,"[/twitter]",$start+9);
                        if ($end === false) break;
                        $tweet = trim(substr($content,$start+9,$end-$start-9));
                        $last = $end + 10;
                        $content = substr_replace($content
                                ,"<blockquote class=\"twitter-tweet\"><a href=\""
                                . $tweet
                                . "\"</a></blockquote>"
                                ,$start,$last-$start);
                }
                return $content;

        }

        /**
         * Parse raw content and return HTML
         * @param string $content
         * @return string
         */
        public function toHtml($content) {
                $arr = explode("`",$content);   // known deficiency: does not cope for HTML comments
                // even elements can be changed, uneven are code-block elements
                for($i=0, $size=count($arr); $i<$size; $i+=2) {
                        $arr[$i] = $this->displayMath($arr[$i]);
                        $arr[$i] = $this->inlineMath($arr[$i]);
                        $arr[$i] = $this->youtube($arr[$i]);
                        $arr[$i] = $this->twitter($arr[$i]);
                }
                return parent::toHtml(implode("`",$arr));       // markdown to HTML
        }
}

The following JavaScript libraries have to be present in layout.blade.php:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>
        @hasSection('title')
        @yield('title') - Saaze
        @else
        Saaze
        @endif
    </title>
    <link rel="stylesheet" href="https://unpkg.com/tailwindcss@^2.1.0/dist/base.min.css" />
    <link rel="stylesheet" href="https://unpkg.com/tailwindcss@^2.1.0/dist/components.min.css" />
    <link rel="stylesheet" href="https://unpkg.com/@tailwindcss/typography@0.2.x/dist/typography.min.css" />
    <link rel="stylesheet" href="https://unpkg.com/tailwindcss@^2.1.0/dist/utilities.min.css" />
    <link href="https://unpkg.com/prismjs@v1.23.0/themes/prism.css" rel="stylesheet" />
    <link href="https://unpkg.com/prismjs@v1.23.0/plugins/line-numbers/prism-line-numbers.css" rel="stylesheet" />
    <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
    <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
    <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
    <script src="https://unpkg.com/prismjs@v1.23.0/components/prism-core.min.js"></script>
    <script src="https://unpkg.com/prismjs@v1.23.0/plugins/autoloader/prism-autoloader.min.js"></script>
    <script src="https://unpkg.com/prismjs@v1.23.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
</head>
<body class="line-numbers">
    <header class="p-6 sm:px-10 sm:flex sm:justify-between sm:items-center mb-10 sm:mb-20">
        <div class="mb-4 sm:mb-0">
            <a href="/" class="text-xl text-purple-600">Saaze</a>
        </div>
        <nav>
            <ul class="flex">
                <li><a href="{{ $GLOBALS['rbase'] }}/" class="text-purple-600">Home</a></li>
                <li class="ml-10"><a href="{{ $GLOBALS['rbase'] }}/about" class="text-purple-600">About</a></li>
                <li class="ml-10"><a href="{{ $GLOBALS['rbase'] }}/blog" class="text-purple-600">Blog</a></li>
            </ul>
        </nav>
    </header>
    <div class="font-serif prose prose-sm sm:prose lg:prose-lg xl:prose-xl mx-auto px-6 my-10 sm:my-20">
        @yield('content')
    </div>
    <footer class="prose prose-sm sm:prose lg:prose-lg xl:prose-xl mx-auto px-6 my-20 sm:my-32">
        <p class="text-center text-gray-600 text-xs sm:text-base">Copyright &copy; {{ date('Y') }}</p>
    </footer>
</body>

</html>

Prism.js or font-change is not required for this extension. I added it anyway, as my blog contains some code snippets.