diff --git a/.gitignore b/.gitignore index 0d7e731..c1776c1 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,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/images/ttp-gitlab.png b/app/images/ttp-gitlab.png index 9637ee2..1bce8fa 100644 Binary files a/app/images/ttp-gitlab.png and b/app/images/ttp-gitlab.png differ diff --git a/app/js/main.js b/app/js/main.js index 5735782..d139f12 100644 --- a/app/js/main.js +++ b/app/js/main.js @@ -8,6 +8,63 @@ * @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.remove("d-none"); + installPrompt.classList.add("d-block"); // 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("d-block"); + installPrompt.classList.add("d-none"); + } + }); +} + +// 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("d-block"); // Hide the prompt + installPrompt.classList.add("d-none"); +} + +// Check if the 7-day period has passed +if (localStorage.getItem("pwaInstallDismissed")) { + const dismissUntil = parseInt(localStorage.getItem("pwaInstallDismissed"), 10); + if (Date.now() < dismissUntil) { + // + } 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 848ab67..55a9dd5 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..200ae97 --- /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 3c82011..52c2cc4 100644 --- a/bin/tempus_project.php +++ b/bin/tempus_project.php @@ -313,7 +313,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" => [ @@ -329,6 +335,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/composer.json b/composer.json index 7defb33..8f2d095 100644 --- a/composer.json +++ b/composer.json @@ -23,8 +23,9 @@ ], "require": { + "endroid/qr-code": "^6.0", "fortawesome/font-awesome": "4.7", - "thetempusproject/bedrock": "1.1.5", + "thetempusproject/bedrock": "1.1.6", "thetempusproject/canary": "1.0.9", "thetempusproject/houdini": "2.0.5", "twbs/bootstrap": "5.2.3" diff --git a/composer.lock b/composer.lock index 7406a3a..c361252 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "63640223834a7eeb9b4a211cd45cc6df", + "content-hash": "10e7ce6b744b46b0c10780dbd7786ecb", "packages": [ { "name": "bacon/bacon-qr-code", @@ -60,58 +60,6 @@ }, "time": "2024-10-01T13:55:55+00:00" }, - { - "name": "components/jquery", - "version": "1.9.1", - "source": { - "type": "git", - "url": "https://github.com/components/jquery.git", - "reference": "ae5c0c13cf163b3751ce55f9d9e97c1ba7ff796d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/components/jquery/zipball/ae5c0c13cf163b3751ce55f9d9e97c1ba7ff796d", - "reference": "ae5c0c13cf163b3751ce55f9d9e97c1ba7ff796d", - "shasum": "" - }, - "require": { - "robloach/component-installer": "*" - }, - "type": "component", - "extra": { - "component": { - "files": [ - "jquery.min.js", - "jquery-migrate.js", - "jquery-migrate.min.js", - "jquery.min.map" - ], - "scripts": [ - "jquery.js" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Resig", - "email": "jeresig@gmail.com" - } - ], - "description": "jQuery JavaScript Library", - "homepage": "http://jquery.com", - "support": { - "forum": "http://forum.jquery.com", - "irc": "irc://irc.freenode.org/jquery", - "issues": "http://bugs.jquery.com", - "source": "https://github.com/jquery/jquery", - "wiki": "http://docs.jquery.com/" - }, - "time": "2014-10-11T11:52:45+00:00" - }, { "name": "dasprid/enum", "version": "1.0.6", @@ -286,204 +234,13 @@ }, "time": "2016-10-24T15:52:54+00:00" }, - { - "name": "kriswallsmith/assetic", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/kriswallsmith/assetic.git", - "reference": "e911c437dbdf006a8f62c2f59b15b2d69a5e0aa1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kriswallsmith/assetic/zipball/e911c437dbdf006a8f62c2f59b15b2d69a5e0aa1", - "reference": "e911c437dbdf006a8f62c2f59b15b2d69a5e0aa1", - "shasum": "" - }, - "require": { - "php": ">=5.3.1", - "symfony/process": "~2.1|~3.0" - }, - "conflict": { - "twig/twig": "<1.27" - }, - "require-dev": { - "leafo/lessphp": "^0.3.7", - "leafo/scssphp": "~0.1", - "meenie/javascript-packer": "^1.1", - "mrclay/minify": "<2.3", - "natxet/cssmin": "3.0.4", - "patchwork/jsqueeze": "~1.0|~2.0", - "phpunit/phpunit": "~4.8 || ^5.6", - "psr/log": "~1.0", - "ptachoire/cssembed": "~1.0", - "symfony/phpunit-bridge": "~2.7|~3.0", - "twig/twig": "~1.23|~2.0", - "yfix/packager": "dev-master" - }, - "suggest": { - "leafo/lessphp": "Assetic provides the integration with the lessphp LESS compiler", - "leafo/scssphp": "Assetic provides the integration with the scssphp SCSS compiler", - "leafo/scssphp-compass": "Assetic provides the integration with the SCSS compass plugin", - "patchwork/jsqueeze": "Assetic provides the integration with the JSqueeze JavaScript compressor", - "ptachoire/cssembed": "Assetic provides the integration with phpcssembed to embed data uris", - "twig/twig": "Assetic provides the integration with the Twig templating engine" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-0": { - "Assetic": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kris Wallsmith", - "email": "kris.wallsmith@gmail.com", - "homepage": "http://kriswallsmith.net/" - } - ], - "description": "Asset Management for PHP", - "homepage": "https://github.com/kriswallsmith/assetic", - "keywords": [ - "assets", - "compression", - "minification" - ], - "support": { - "issues": "https://github.com/kriswallsmith/assetic/issues", - "source": "https://github.com/kriswallsmith/assetic/tree/master" - }, - "time": "2016-11-11T18:43:20+00:00" - }, - { - "name": "robloach/component-installer", - "version": "0.0.12", - "source": { - "type": "git", - "url": "https://github.com/RobLoach/component-installer.git", - "reference": "1864f25db21fc173e02a359f646acd596c1b0460" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/RobLoach/component-installer/zipball/1864f25db21fc173e02a359f646acd596c1b0460", - "reference": "1864f25db21fc173e02a359f646acd596c1b0460", - "shasum": "" - }, - "require": { - "kriswallsmith/assetic": "1.*", - "php": ">=5.3.2" - }, - "require-dev": { - "composer/composer": "1.*" - }, - "type": "composer-installer", - "extra": { - "class": "ComponentInstaller\\Installer" - }, - "autoload": { - "psr-0": { - "ComponentInstaller": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Rob Loach", - "email": "robloach@gmail.com", - "homepage": "http://robloach.net" - } - ], - "description": "Allows installation of Components via Composer.", - "support": { - "issues": "https://github.com/RobLoach/component-installer/issues", - "source": "https://github.com/RobLoach/component-installer/tree/master" - }, - "abandoned": "oomphinc/composer-installers-extender", - "time": "2013-08-31T23:46:48+00:00" - }, - { - "name": "symfony/process", - "version": "v3.4.47", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/b8648cf1d5af12a44a51d07ef9bf980921f15fca", - "reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Process Component", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v3.4.47" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-24T10:57:07+00:00" - }, { "name": "thetempusproject/bedrock", - "version": "1.1.5", + "version": "1.1.6", "source": { "type": "git", "url": "https://git.thetempusproject.com/the-tempus-project/bedrock", - "reference": "39d350df061b4c69266bbbe152976cf7254e4c08" + "reference": "cfa53c9e7058f78559ee8615431645c7eef972f8" }, "require": { "php": ">=8.1.0", @@ -522,7 +279,7 @@ "php", "thetempusproject" ], - "time": "2025-02-04T12:20:56+00:00" + "time": "2025-02-06T03:02:46+00:00" }, { "name": "thetempusproject/canary", diff --git a/images/icon-maskWhite.png b/images/icon-maskWhite.png new file mode 100644 index 0000000..d93d196 Binary files /dev/null and b/images/icon-maskWhite.png differ