WIP on vanilla PHP framework
This commit is contained in:
		
							parent
							
								
									24c503385e
								
							
						
					
					
						commit
						41853a7645
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -256,3 +256,6 @@ paket-files/
 | 
			
		||||
.ionide
 | 
			
		||||
 | 
			
		||||
src/environment.txt
 | 
			
		||||
 | 
			
		||||
# PHP ignore files
 | 
			
		||||
src/vendor
 | 
			
		||||
 | 
			
		||||
@ -8,9 +8,4 @@ myPrayerJournal was borne of out of a personal desire [Daniel](https://github.co
 | 
			
		||||
 | 
			
		||||
## Further Reading
 | 
			
		||||
 | 
			
		||||
The documentation for the site is at <https://bit-badger.github.io/myPrayerJournal/>.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
_Thanks to [JetBrains](https://jb.gg/OpenSource) for licensing their awesome toolset to this project._
 | 
			
		||||
 | 
			
		||||
[<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.png" alt="JetBrains Logo (Main) logo" width="100" height="100">](https://jb.gg/OpenSource)
 | 
			
		||||
The documentation for the site is at <https://prayerjournal.me/docs>.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								src/composer.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/composer.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "bit-badger/my-prayer-journal",
 | 
			
		||||
  "minimum-stability": "dev",
 | 
			
		||||
  "require": {
 | 
			
		||||
    "php": ">=8.2",
 | 
			
		||||
    "ext-pdo": "*",
 | 
			
		||||
    "ext-sqlite3": "*",
 | 
			
		||||
    "bit-badger/pdo-document": "^1",
 | 
			
		||||
    "visus/cuid2": "^4"
 | 
			
		||||
  },
 | 
			
		||||
  "autoload": {
 | 
			
		||||
    "psr-4": {
 | 
			
		||||
      "MyPrayerJournal\\": "lib/"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										182
									
								
								src/composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,182 @@
 | 
			
		||||
{
 | 
			
		||||
    "_readme": [
 | 
			
		||||
        "This file locks the dependencies of your project to a known state",
 | 
			
		||||
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
 | 
			
		||||
        "This file is @generated automatically"
 | 
			
		||||
    ],
 | 
			
		||||
    "content-hash": "aa94d32d1f21c70c88434971a9dba5a8",
 | 
			
		||||
    "packages": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "bit-badger/pdo-document",
 | 
			
		||||
            "version": "v1.0.0-alpha2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://git.bitbadger.solutions/bit-badger/pdo-document",
 | 
			
		||||
                "reference": "330e27218756df8b93081a17dead8aaec789b071"
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "ext-pdo": "*",
 | 
			
		||||
                "netresearch/jsonmapper": "^4",
 | 
			
		||||
                "php": ">=8.2"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "phpunit/phpunit": "^11"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "BitBadger\\PDODocument\\": "./src",
 | 
			
		||||
                    "BitBadger\\PDODocument\\Query\\": "./src/Query",
 | 
			
		||||
                    "BitBadger\\PDODocument\\Mapper\\": "./src/Mapper"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Daniel J. Summers",
 | 
			
		||||
                    "email": "daniel@bitbadger.solutions",
 | 
			
		||||
                    "homepage": "https://bitbadger.solutions",
 | 
			
		||||
                    "role": "Developer"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Treat SQLite (and soon PostgreSQL) as a document store",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "database",
 | 
			
		||||
                "document",
 | 
			
		||||
                "pdo",
 | 
			
		||||
                "sqlite"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "email": "daniel@bitbadger.solutions",
 | 
			
		||||
                "rss": "https://git.bitbadger.solutions/bit-badger/pdo-document.rss",
 | 
			
		||||
                "source": "https://git.bitbadger.solutions/bit-badger/pdo-document"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2024-06-11T11:07:56+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "netresearch/jsonmapper",
 | 
			
		||||
            "version": "v4.4.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/cweiske/jsonmapper.git",
 | 
			
		||||
                "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0",
 | 
			
		||||
                "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "ext-json": "*",
 | 
			
		||||
                "ext-pcre": "*",
 | 
			
		||||
                "ext-reflection": "*",
 | 
			
		||||
                "ext-spl": "*",
 | 
			
		||||
                "php": ">=7.1"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
 | 
			
		||||
                "squizlabs/php_codesniffer": "~3.5"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-0": {
 | 
			
		||||
                    "JsonMapper": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "OSL-3.0"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Christian Weiske",
 | 
			
		||||
                    "email": "cweiske@cweiske.de",
 | 
			
		||||
                    "homepage": "http://github.com/cweiske/jsonmapper/",
 | 
			
		||||
                    "role": "Developer"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Map nested JSON structures onto PHP classes",
 | 
			
		||||
            "support": {
 | 
			
		||||
                "email": "cweiske@cweiske.de",
 | 
			
		||||
                "issues": "https://github.com/cweiske/jsonmapper/issues",
 | 
			
		||||
                "source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2024-01-31T06:18:54+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "visus/cuid2",
 | 
			
		||||
            "version": "4.1.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/visus-io/php-cuid2.git",
 | 
			
		||||
                "reference": "17c9b3098d556bb2556a084c948211333cc19c79"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/visus-io/php-cuid2/zipball/17c9b3098d556bb2556a084c948211333cc19c79",
 | 
			
		||||
                "reference": "17c9b3098d556bb2556a084c948211333cc19c79",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": "^8.1"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "ergebnis/composer-normalize": "^2.29",
 | 
			
		||||
                "ext-ctype": "*",
 | 
			
		||||
                "phpstan/phpstan": "^1.9",
 | 
			
		||||
                "phpunit/phpunit": "^10.0",
 | 
			
		||||
                "squizlabs/php_codesniffer": "^3.7",
 | 
			
		||||
                "vimeo/psalm": "^5.4"
 | 
			
		||||
            },
 | 
			
		||||
            "suggest": {
 | 
			
		||||
                "ext-gmp": "*"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "files": [
 | 
			
		||||
                    "src/compat.php"
 | 
			
		||||
                ],
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Visus\\Cuid2\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Alan Brault",
 | 
			
		||||
                    "email": "alan.brault@visus.io"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "A PHP library for generating collision-resistant ids (CUIDs).",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "cuid",
 | 
			
		||||
                "identifier"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/visus-io/php-cuid2/issues",
 | 
			
		||||
                "source": "https://github.com/visus-io/php-cuid2/tree/4.1.0"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2024-05-14T13:23:35+00:00"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "packages-dev": [],
 | 
			
		||||
    "aliases": [],
 | 
			
		||||
    "minimum-stability": "dev",
 | 
			
		||||
    "stability-flags": [],
 | 
			
		||||
    "prefer-stable": false,
 | 
			
		||||
    "prefer-lowest": false,
 | 
			
		||||
    "platform": {
 | 
			
		||||
        "php": ">=8.2",
 | 
			
		||||
        "ext-pdo": "*",
 | 
			
		||||
        "ext-sqlite3": "*"
 | 
			
		||||
    },
 | 
			
		||||
    "platform-dev": [],
 | 
			
		||||
    "plugin-api-version": "2.6.0"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/lib/History.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/lib/History.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
<?php declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace MyPrayerJournal;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A record of an action taken on a request
 | 
			
		||||
 */
 | 
			
		||||
class History
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string $asOf The date/time this entry was made
 | 
			
		||||
     * @param RequestAction $action The action taken for this history entry
 | 
			
		||||
     * @param string|null $text The text for this history entry (optional)
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(public string $asOf, public RequestAction $action, public ?string $text = null) { }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								src/lib/Note.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/lib/Note.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace MyPrayerJournal;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A note entered on a prayer request
 | 
			
		||||
 */
 | 
			
		||||
class Note
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string $asOf The date/time this note was recorded
 | 
			
		||||
     * @param string $text The text of the note
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(public string $asOf, public string $text) { }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								src/lib/Recurrence.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/lib/Recurrence.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace MyPrayerJournal;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The recurrence for a prayer request
 | 
			
		||||
 */
 | 
			
		||||
class Recurrence
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @param RecurrencePeriod $period The recurrence period
 | 
			
		||||
     * @param int|null $interval How many of the periods will pass before the request is visible again
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(public RecurrencePeriod $period, public ?int $interval = null) { }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/lib/RecurrencePeriod.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/lib/RecurrencePeriod.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
<?php declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace MyPrayerJournal;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The type of recurrence a request can have
 | 
			
		||||
 */
 | 
			
		||||
enum RecurrencePeriod
 | 
			
		||||
{
 | 
			
		||||
    /** Requests, once prayed, are available again immediately */
 | 
			
		||||
    case Immediate;
 | 
			
		||||
 | 
			
		||||
    /** Requests, once prayed, appear again in a number of hours */
 | 
			
		||||
    case Hours;
 | 
			
		||||
 | 
			
		||||
    /** Requests, once prayed, appear again in a number of days */
 | 
			
		||||
    case Days;
 | 
			
		||||
 | 
			
		||||
    /** Requests, once prayed, appear again in a number of weeks */
 | 
			
		||||
    case Weeks;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								src/lib/Request.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/lib/Request.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
<?php declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace MyPrayerJournal;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use Visus\Cuid2\Cuid2;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A prayer request
 | 
			
		||||
 */
 | 
			
		||||
class Request
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string $id The ID for the request
 | 
			
		||||
     * @param string $enteredOn The date/time this request was originally entered
 | 
			
		||||
     * @param string $userId The ID of the user to whom this request belongs
 | 
			
		||||
     * @param string|null $snoozedUntil The date/time the snooze expires for this request (null = not snoozed)
 | 
			
		||||
     * @param string|null $showAfter The date/time the current recurrence period is over (null = immediate)
 | 
			
		||||
     * @param Recurrence $recurrence The recurrence for this request
 | 
			
		||||
     * @param array|History[] $history The history of this request
 | 
			
		||||
     * @param array|Note[] $notes Notes regarding this request
 | 
			
		||||
     * @throws Exception If the ID generation fails
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(public string $id = '', public string $enteredOn = '', public string $userId = '',
 | 
			
		||||
                                public ?string $snoozedUntil = null, public ?string $showAfter = null,
 | 
			
		||||
                                public Recurrence $recurrence = new Recurrence(RecurrencePeriod::Immediate),
 | 
			
		||||
                                public array $history = [], public array $notes = [])
 | 
			
		||||
    {
 | 
			
		||||
        if ($id == '') {
 | 
			
		||||
            $this->id = (new Cuid2())->toString();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/lib/RequestAction.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/lib/RequestAction.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
<?php declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace MyPrayerJournal;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An action taken on a prayer request
 | 
			
		||||
 */
 | 
			
		||||
enum RequestAction
 | 
			
		||||
{
 | 
			
		||||
    /** The request was created */
 | 
			
		||||
    case Created;
 | 
			
		||||
 | 
			
		||||
    /** The request was marked as having been prayed for */
 | 
			
		||||
    case Prayed;
 | 
			
		||||
 | 
			
		||||
    /** The request was updated */
 | 
			
		||||
    case Updated;
 | 
			
		||||
 | 
			
		||||
    /** The request was marked as answered */
 | 
			
		||||
    case Answered;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								src/public/index.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/public/index.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
require '../start.php';
 | 
			
		||||
 | 
			
		||||
html_head('Welcome'); ?>
 | 
			
		||||
<article class="container mt-3">
 | 
			
		||||
    <p> 
 | 
			
		||||
    <p>myPrayerJournal is a place where individuals can record their prayer requests, record that they prayed for them,
 | 
			
		||||
        update them as God moves in the situation, and record a final answer received on that request. It also allows
 | 
			
		||||
        individuals to review their answered prayers.
 | 
			
		||||
    <p>This site is open and available for anyone who wants to use it. To get started, simply click the “Log
 | 
			
		||||
        On” link above, and log on with either a Microsoft or Google account. You can also learn more about the
 | 
			
		||||
        site at the “Docs” link, also above.
 | 
			
		||||
</article><?php
 | 
			
		||||
html_foot();
 | 
			
		||||
							
								
								
									
										7
									
								
								src/public/script/bootstrap.bundle.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/public/script/bootstrap.bundle.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								src/public/script/htmx.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/public/script/htmx.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										104
									
								
								src/public/script/mpj.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/public/script/mpj.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,104 @@
 | 
			
		||||
"use strict"
 | 
			
		||||
 | 
			
		||||
/** myPrayerJournal script */
 | 
			
		||||
this.mpj = {
 | 
			
		||||
  /**
 | 
			
		||||
   * Show a message via toast
 | 
			
		||||
   * @param {string} message The message to show
 | 
			
		||||
   */
 | 
			
		||||
  showToast (message) {
 | 
			
		||||
    const [level, msg] = message.split("|||")
 | 
			
		||||
    
 | 
			
		||||
    let header
 | 
			
		||||
    if (level !== "success") {
 | 
			
		||||
      const heading = typ => `<span class="me-auto"><strong>${typ.toUpperCase()}</strong></span>`
 | 
			
		||||
      
 | 
			
		||||
      header = document.createElement("div")
 | 
			
		||||
      header.className = "toast-header"
 | 
			
		||||
      header.innerHTML = heading(level === "warning" ? level : "error")
 | 
			
		||||
      
 | 
			
		||||
      const close = document.createElement("button")
 | 
			
		||||
      close.type = "button"
 | 
			
		||||
      close.className = "btn-close"
 | 
			
		||||
      close.setAttribute("data-bs-dismiss", "toast")
 | 
			
		||||
      close.setAttribute("aria-label", "Close")
 | 
			
		||||
      header.appendChild(close)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const body = document.createElement("div")
 | 
			
		||||
    body.className = "toast-body"
 | 
			
		||||
    body.innerText = msg
 | 
			
		||||
    
 | 
			
		||||
    const toastEl = document.createElement("div")
 | 
			
		||||
    toastEl.className = `toast bg-${level === "error" ? "danger" : level} text-white`
 | 
			
		||||
    toastEl.setAttribute("role", "alert")
 | 
			
		||||
    toastEl.setAttribute("aria-live", "assertlive")
 | 
			
		||||
    toastEl.setAttribute("aria-atomic", "true")
 | 
			
		||||
    toastEl.addEventListener("hidden.bs.toast", e => e.target.remove())
 | 
			
		||||
    if (header) toastEl.appendChild(header)
 | 
			
		||||
    
 | 
			
		||||
    toastEl.appendChild(body)
 | 
			
		||||
    document.getElementById("toasts").appendChild(toastEl)
 | 
			
		||||
    new bootstrap.Toast(toastEl, { autohide: level === "success" }).show()
 | 
			
		||||
  },
 | 
			
		||||
  /**
 | 
			
		||||
   * Load local version of Bootstrap CSS if the CDN load failed
 | 
			
		||||
   */
 | 
			
		||||
  ensureCss () {
 | 
			
		||||
    let loaded = false
 | 
			
		||||
    for (let i = 0; !loaded && i < document.styleSheets.length; i++) {
 | 
			
		||||
      loaded = document.styleSheets[i].href.endsWith("bootstrap.min.css")
 | 
			
		||||
    }
 | 
			
		||||
    if (!loaded) {
 | 
			
		||||
      const css = document.createElement("link")
 | 
			
		||||
      css.rel = "stylesheet"
 | 
			
		||||
      css.href = "/style/bootstrap.min.css"
 | 
			
		||||
      document.getElementsByTagName("head")[0].appendChild(css)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  /** Script for the request edit component */
 | 
			
		||||
  edit: {
 | 
			
		||||
    /**
 | 
			
		||||
     * Toggle the recurrence input fields
 | 
			
		||||
     * @param {Event} e The click event
 | 
			
		||||
     */
 | 
			
		||||
    toggleRecurrence ({ target }) {
 | 
			
		||||
      const isDisabled = target.value === "Immediate"
 | 
			
		||||
      ;["recurCount", "recurInterval"].forEach(it => document.getElementById(it).disabled = isDisabled)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  /**
 | 
			
		||||
   * The time zone of the current browser
 | 
			
		||||
   * @type {string}
 | 
			
		||||
   **/
 | 
			
		||||
  timeZone: undefined,
 | 
			
		||||
  /**
 | 
			
		||||
   * Derive the time zone from the current browser
 | 
			
		||||
   */
 | 
			
		||||
  deriveTimeZone () {
 | 
			
		||||
    try {
 | 
			
		||||
      this.timeZone = (new Intl.DateTimeFormat()).resolvedOptions().timeZone
 | 
			
		||||
    } catch (_) { }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
htmx.on("htmx:afterOnLoad", function (evt) {
 | 
			
		||||
  const hdrs = evt.detail.xhr.getAllResponseHeaders()
 | 
			
		||||
  // Show a message if there was one in the response
 | 
			
		||||
  if (hdrs.indexOf("x-toast") >= 0) {
 | 
			
		||||
    mpj.showToast(evt.detail.xhr.getResponseHeader("x-toast"))
 | 
			
		||||
  }
 | 
			
		||||
  // Hide a modal window if requested
 | 
			
		||||
  if (hdrs.indexOf("x-hide-modal") >= 0) {
 | 
			
		||||
    document.getElementById(evt.detail.xhr.getResponseHeader("x-hide-modal") + "Dismiss").click()
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
htmx.on("htmx:configRequest", function (evt) {
 | 
			
		||||
  // Send the user's current time zone so that we can display local time
 | 
			
		||||
  if (mpj.timeZone) {
 | 
			
		||||
    evt.detail.headers["X-Time-Zone"] = mpj.timeZone
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
mpj.deriveTimeZone()
 | 
			
		||||
							
								
								
									
										57
									
								
								src/public/style/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/public/style/style.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
 | 
			
		||||
nav {
 | 
			
		||||
  background-color: green;
 | 
			
		||||
}
 | 
			
		||||
nav .m {
 | 
			
		||||
  font-weight: 100;
 | 
			
		||||
}
 | 
			
		||||
nav .p {
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
}
 | 
			
		||||
nav .j {
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
}
 | 
			
		||||
.nav-item a:link,
 | 
			
		||||
.nav-item a:visited {
 | 
			
		||||
  padding: .5rem 1rem;
 | 
			
		||||
  margin: 0 .5rem;
 | 
			
		||||
  border-radius: .5rem;
 | 
			
		||||
  color: white;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
.nav-item a:hover {
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  background-color: rgba(255, 255, 255, .2);
 | 
			
		||||
}
 | 
			
		||||
.nav-item a.is-active-route {
 | 
			
		||||
  border-top-left-radius: 0;
 | 
			
		||||
  border-top-right-radius: 0;
 | 
			
		||||
  border-top: solid 4px rgba(255, 255, 255, .3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
form {
 | 
			
		||||
  max-width: 60rem;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
.action-cell .material-icons {
 | 
			
		||||
  font-size: 1.1rem ;
 | 
			
		||||
}
 | 
			
		||||
.material-icons {
 | 
			
		||||
  vertical-align: bottom;
 | 
			
		||||
}
 | 
			
		||||
#toastHost {
 | 
			
		||||
  position: sticky;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
.request-text {
 | 
			
		||||
  white-space: pre-line
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
footer {
 | 
			
		||||
  border-top: solid 1px lightgray;
 | 
			
		||||
  margin: 1rem -1rem 0;
 | 
			
		||||
  padding: 0 1rem;
 | 
			
		||||
}
 | 
			
		||||
footer p {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								src/start.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/start.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
<?php declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
const MPJ_VERSION = '4.0.0';
 | 
			
		||||
 | 
			
		||||
function html_head(string $title): void
 | 
			
		||||
{ ?>
 | 
			
		||||
    <!DOCTYPE html>
 | 
			
		||||
    <head lang=en>
 | 
			
		||||
        <meta name=viewport content="width=device-width, initial-scale=1">
 | 
			
		||||
        <meta name=description content="Online prayer journal - free w/Google or Microsoft account">
 | 
			
		||||
        <title><?=$title?> « myPrayerJournal</title>
 | 
			
		||||
        <link href=https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css rel=stylesheet
 | 
			
		||||
              integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin=anonymous>
 | 
			
		||||
        <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel=stylesheet>
 | 
			
		||||
        <link href=/style/style.css rel=stylesheet>
 | 
			
		||||
    </head><?php
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function page_link(string $href, string $text, array $attrs = []): void
 | 
			
		||||
{ ?>
 | 
			
		||||
    <a href="<?=$href?>" hx-get="<?=$href?>" hx-target="#top" hx-swap=innerHTML hx-push-url=true<?php
 | 
			
		||||
        foreach ($attrs as $key => $value) echo " $key=\"" . htmlspecialchars($value) . "\""; ?>><?=$text?></a><?php
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function html_foot(): void
 | 
			
		||||
{
 | 
			
		||||
    $version = MPJ_VERSION;
 | 
			
		||||
    while (!str_ends_with($version, '.0')) $version = substr($version, 0, strlen($version) - 2); ?>
 | 
			
		||||
    <footer class=container-fluid>
 | 
			
		||||
        <p class="text-muted text-end">
 | 
			
		||||
            myPrayerJournal <?=$version?><br>
 | 
			
		||||
            <em>
 | 
			
		||||
                <small><?php
 | 
			
		||||
                    page_link('/legal/privacy-policy', 'Privacy Policy');
 | 
			
		||||
                    echo ' • ';
 | 
			
		||||
                    page_link('/legal/terms-of-service', 'Terms of Service');
 | 
			
		||||
                    echo ' • '; ?>
 | 
			
		||||
                    <a href=https://git.bitbadger.solutions/bit-badger/myPrayerJournal target=_blank
 | 
			
		||||
                       rel=noopener>Developed</a> and hosted by
 | 
			
		||||
                    <a href=https://bitbadger.solutions target=_blank rel=noopener>Bit Badger Solutions</a>
 | 
			
		||||
                </small>
 | 
			
		||||
            </em>
 | 
			
		||||
            Htmx.Script.minified
 | 
			
		||||
            <script>if (!htmx) document.write('<script src=\"/script/htmx.min.js\"><\/script>')</script>
 | 
			
		||||
            <script async src=https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js
 | 
			
		||||
                    integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
 | 
			
		||||
                    crossorigin=anonymous></script>
 | 
			
		||||
            <script>
 | 
			
		||||
                setTimeout(function () {
 | 
			
		||||
                    if (!bootstrap) document.write('<script src=\"/script/bootstrap.bundle.min.js\"><\/script>')
 | 
			
		||||
                }, 2000)
 | 
			
		||||
            </script>
 | 
			
		||||
            <script src=/script/mpj.js></script>
 | 
			
		||||
    </footer><?php
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user