From a6b241c7f0ff104fdf56f6d289e1d6603d72403b Mon Sep 17 00:00:00 2001 From: Joey Kimsey Date: Wed, 5 Feb 2025 19:39:54 -0500 Subject: [PATCH] add qr-codes, share button, and pwa config toggle --- .gitignore | 1 + app/controllers/admin/images.php | 62 --------------------------- app/js/main.js | 55 ++++++++++++++++++++++++ app/templates/default/default.inc.php | 58 +++++++++++++++++++++++++ app/templates/default/default.tpl | 1 + app/views/footer/right.html | 1 + app/views/footer/share.html | 17 ++++++++ app/views/pwa.html | 11 +++++ bin/tempus_project.php | 22 +++++++++- install.php | 6 +-- 10 files changed, 168 insertions(+), 66 deletions(-) create mode 100644 app/views/footer/share.html create mode 100644 app/views/pwa.html diff --git a/.gitignore b/.gitignore index 2c74cbb..9bc33e0 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,4 @@ vendor/canary/logs/* components/* mailhog.log uploads/* +images/qr-codes/ diff --git a/app/controllers/admin/images.php b/app/controllers/admin/images.php index 690cdaf..20ca7b1 100644 --- a/app/controllers/admin/images.php +++ b/app/controllers/admin/images.php @@ -76,25 +76,6 @@ class Images extends AdminController { Views::view( 'admin.images.upload' ); } - - - - - - - - - - - - - - - - - - - private function getFolderObject( $folder, $subdirs = '' ) { $names = explode( DIRECTORY_SEPARATOR, $folder ); $folderName = array_pop( $names ); @@ -155,28 +136,6 @@ class Images extends AdminController { return $dirs; } - - - - - - - - - - - - - - - - - - - - - - public function __construct() { parent::__construct(); self::$title = 'Admin - Images'; @@ -204,25 +163,6 @@ class Images extends AdminController { Debug::error( 'There was an error with your upload.'); Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] ); } - - - - - - - - - - // if ( self::$token->create( - // Input::post( 'name' ), - // Input::post( 'notes' ), - // Input::post( 'token_type' ) - // ) ) { - // Session::flash( 'success', 'Token Created' ); - // Redirect::to( 'admin/images' ); - // } - - } Views::view( 'admin.images.create' ); } @@ -261,7 +201,6 @@ class Images extends AdminController { } public function rename() { - if ( ! Input::exists( 'fileLocation' ) ) { Session::flash( 'warning', 'Unknown image.' ); Redirect::to( 'admin/images' ); @@ -274,7 +213,6 @@ class Images extends AdminController { Issues::add( 'error', [ 'There was an error renaming the image.' => Check::userErrors() ] ); } else { $result = $this->renameFile( Input::post( 'filelocation' ), Input::post( 'newname' ) ); - if ( ! empty( $result ) ) { Session::flash( 'success', 'Image has been renamed.' ); Redirect::to( 'admin/images' ); diff --git a/app/js/main.js b/app/js/main.js index c22fc1f..052d3b9 100644 --- a/app/js/main.js +++ b/app/js/main.js @@ -8,6 +8,61 @@ * @link https://TheTempusProject.com * @license https://opensource.org/licenses/MIT [MIT LICENSE] */ + +let deferredPrompt; +const installPrompt = document.getElementById("install-prompt"); +const installButton = document.getElementById("install-button"); +const dismissButton = document.querySelector("#install-prompt .btn-close"); + +// Check if the user previously dismissed the prompt +if (!localStorage.getItem("pwaInstallDismissed")) { + window.addEventListener("beforeinstallprompt", (event) => { + event.preventDefault(); + deferredPrompt = event; + installPrompt.classList.add("show"); // Show the prompt + }); +} + +// Handle Install Button Click +if ( installButton ) { + installButton.addEventListener("click", async () => { + if (deferredPrompt) { + deferredPrompt.prompt(); + const { outcome } = await deferredPrompt.userChoice; + + if (outcome === "dismissed") { + setInstallDismissed(); // Store that the user dismissed the prompt + } + + deferredPrompt = null; // Reset prompt + installPrompt.classList.remove("show"); // Hide the prompt + } + }); +} + +// Handle Close Button Click +if ( dismissButton ) { + dismissButton.addEventListener("click", () => { + setInstallDismissed(); // Store that the user dismissed the prompt + }); +} + +// Function to remember user choice for 7 days +function setInstallDismissed() { + localStorage.setItem("pwaInstallDismissed", Date.now() + 7 * 24 * 60 * 60 * 1000); + installPrompt.classList.remove("show"); // Hide the prompt +} + +// Check if the 7-day period has passed +if (localStorage.getItem("pwaInstallDismissed")) { + const dismissUntil = parseInt(localStorage.getItem("pwaInstallDismissed"), 10); + if (Date.now() < dismissUntil) { + installPrompt.classList.remove("show"); // Ensure it's hidden + } else { + localStorage.removeItem("pwaInstallDismissed"); // Reset after 7 days + } +} + /** * Automatically selects/de-selects all check boxes associated with that field **/ diff --git a/app/templates/default/default.inc.php b/app/templates/default/default.inc.php index 95ff8c6..6747556 100644 --- a/app/templates/default/default.inc.php +++ b/app/templates/default/default.inc.php @@ -19,6 +19,15 @@ use TheTempusProject\Houdini\Classes\Components; use TheTempusProject\Bedrock\Classes\Config; use TheTempusProject\Bedrock\Functions\Input; use TheTempusProject\TheTempusProject as App; +use Endroid\QrCode\Builder\Builder; +use Endroid\QrCode\Encoding\Encoding; +use Endroid\QrCode\ErrorCorrectionLevel; +use Endroid\QrCode\Label\LabelAlignment; +use Endroid\QrCode\Label\Font\OpenSans; +use Endroid\QrCode\RoundBlockSizeMode; +use Endroid\QrCode\Writer\PngWriter; +use TheTempusProject\Hermes\Functions\Route as Routes; +use TheTempusProject\Canary\Bin\Canary as Debug; class DefaultLoader extends Loader { private static $loaded = false; @@ -41,12 +50,61 @@ class DefaultLoader extends Loader { } $this->addJs( '' ); Components::setIfNull( 'LOGO', Config::getValue( 'main/logo' ) ?? TP_DEFAULT_LOGO ); + + if ( ! empty( Config::getValue( 'share/enabled' ) ) ) { + $currentUrl = Routes::getAddress() . Input::get( 'url' ); + $folder = IMAGE_DIRECTORY . 'qr-codes' . DIRECTORY_SEPARATOR ; + $filename = md5( $currentUrl ) . '.png'; + + if ( ! file_exists( $folder ) ) { + Debug::Info( 'Creating Directory because it does not exist' ); + mkdir( $folder, 0777, true ); + } + if ( ! empty( Config::getValue( 'share/qr' ) ) ) { + if ( ! file_exists( $folder . $filename ) ) { + Debug::Info( 'Creating qr-image because it does not exist' ); + $builder = new Builder( + writer: new PngWriter(), + writerOptions: [], + validateResult: false, + data: Routes::getAddress() . Input::get( 'url' ), + encoding: new Encoding('UTF-8'), + errorCorrectionLevel: ErrorCorrectionLevel::High, + size: 200, + margin: 10, + roundBlockSizeMode: RoundBlockSizeMode::Margin, + logoPath: APP_ROOT_DIRECTORY . DIRECTORY_SEPARATOR . Config::getValue( 'main/logo' ), + logoResizeToWidth: 30, + logoPunchoutBackground: true, + labelText: Config::getValue( 'main/name' ), + labelFont: new OpenSans(14), + labelAlignment: LabelAlignment::Center + ); + $result = $builder->build(); + $result->saveToFile( $folder . $filename ); + } + Components::set( 'QR_CODE','QR Code' ); + } else { + Components::setIfNull( 'QR_CODE', '' ); + } + Components::setIfNull( 'SHARE_IMAGE', Views::simpleView( 'footer.share' ) ); + } else { + Components::setIfNull( 'SHARE_IMAGE', '' ); + } + + if ( ! empty( Config::getValue( 'main/pwa' ) ) ) { + Components::setIfNull( 'PWA', Views::simpleView( 'pwa') ); + } else { + Components::setIfNull( 'PWA', '' ); + } + Components::setIfNull( 'COPY', Views::simpleView( 'footer.copy') ); Components::setIfNull( 'SOCIAL', Views::simpleView( 'footer.social') ); Components::prepend( 'FOOTER_LEFT', Views::simpleView( 'footer.left', Navigation::getMenuLinks( App::CONTACT_FOOTER_MENU_NAME ) ) ); Components::prepend( 'FOOTER_CENTER', Views::simpleView( 'footer.center', Navigation::getMenuLinks( App::INFO_FOOTER_MENU_NAME ) ) ); Components::prepend( 'FOOTER_RIGHT', Views::simpleView( 'footer.right') ); Components::setIfNull( 'FOOT', Views::simpleView( 'footer.container') ); + /** * Top-Nav */ diff --git a/app/templates/default/default.tpl b/app/templates/default/default.tpl index 2cda303..0e9aa7a 100644 --- a/app/templates/default/default.tpl +++ b/app/templates/default/default.tpl @@ -91,6 +91,7 @@ {/ISSUES} + {PWA} {CONTENT} diff --git a/app/views/footer/right.html b/app/views/footer/right.html index 351f1e5..b17317d 100644 --- a/app/views/footer/right.html +++ b/app/views/footer/right.html @@ -1,4 +1,5 @@
+ {SHARE_IMAGE}
Dark Mode
diff --git a/app/views/footer/share.html b/app/views/footer/share.html new file mode 100644 index 0000000..c642769 --- /dev/null +++ b/app/views/footer/share.html @@ -0,0 +1,17 @@ +
+
Share
+
+ + +
+
\ No newline at end of file diff --git a/app/views/pwa.html b/app/views/pwa.html new file mode 100644 index 0000000..13505f6 --- /dev/null +++ b/app/views/pwa.html @@ -0,0 +1,11 @@ +
+
+ +
+
\ No newline at end of file diff --git a/bin/tempus_project.php b/bin/tempus_project.php index 7779e3c..3d2e2a1 100644 --- a/bin/tempus_project.php +++ b/bin/tempus_project.php @@ -317,7 +317,13 @@ class TheTempusProject extends Bedrock { "pretty" => "Maximum Login session length. (in seconds)", "default" => 604800, // 60 * 60 * 24 * 7 "value" => 604800, // 60 * 60 * 24 * 7 - ] + ], + "pwa" => [ + "type" => "radio", + "pretty" => "Enable PWA banner for installs", + "default" => false, + "value" => false, + ], ], "maintenance" => [ "enabled" => [ @@ -333,6 +339,20 @@ class TheTempusProject extends Bedrock { "value" => "Currently the site is undergoing maintenance. Only administrators will be able to sign in.", ] ], + "share" => [ + "enabled" => [ + "type" => "radio", + "pretty" => "Enables the share popover.", + "default" => false, + "value" => false, + ], + "qr"=> [ + "type" => "radio", + "pretty" => "Enables a custom qr-code in the share popover.", + "default" => false, + "value" => false, + ] + ], "uploads" => [ "images" => [ "type" => "radio", diff --git a/install.php b/install.php index 198feb5..2fdb262 100644 --- a/install.php +++ b/install.php @@ -194,12 +194,12 @@ class Install extends Controller { */ public function configure() { if ( Forms::Check( 'installConfigure' ) ) { - $logo = $baseConfig['main']['template']['default']; + TheTempusProject::$activeConfig->load( BEDROCK_CONFIG_JSON ); + $baseConfig = TheTempusProject::$configMatrix; + $logo = $baseConfig['main']['logo']['default']; if ( Input::exists( 'logo' ) && Upload::image( 'logo', 'System' ) ) { $logo = 'Uploads/Images/System/' . Upload::last(); } - TheTempusProject::$activeConfig->load( BEDROCK_CONFIG_JSON ); - $baseConfig = TheTempusProject::$configMatrix; $baseConfig['main']['logo']['value'] = $logo; $baseConfig['main']['name']['value'] = Input::postNull( 'siteName' ); $baseConfig['database']['dbEnabled']['value'] = $baseConfig['database']['dbEnabled']['default'];