Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
eramitgupta committed Sep 19, 2024
1 parent f552237 commit b6d6adf
Show file tree
Hide file tree
Showing 14 changed files with 498 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
46 changes: 46 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "erag/laravel-pwa",
"description": "A simple and easy-to-use PWA (Progressive Web App) package for Laravel applications.",
"license": "MIT",
"keywords": [
"laravel",
"pwa",
"progressive web app",
"offline",
"service worker",
"manifest",
"laravel package",
"laravel pwa"
],
"authors": [
{
"name": "Er Amiit Gupta",
"email": "info.eramitgupta@gmail.com",
"role": "Developer"
}
],
"require": {
"php": ">=8.0.0",
"illuminate/database": "^8.12|^9.0|^10.0|^11.0",
"illuminate/support": "^8.12|^9.0|^10.0|^11.0"
},
"autoload": {
"files": [
"src/Pwahelpers.php"
],
"psr-4": {
"EragLaravelPwa\\": "src/"
}
},
"prefer-stable": true,
"extra": {
"laravel": {
"providers": [
"EragLaravelPwa\\EragLaravelPwaServiceProvider"
],
"aliases": {
"Pwa": "EragLaravelPwa\\Facades\\Pwa"
}
}
}
}
Binary file added src/.DS_Store
Binary file not shown.
86 changes: 86 additions & 0 deletions src/Commands/PWACommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace EragLaravelPwa\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\File;

class PWACommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'erag:pwa-update-manifest';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Update the manifest.json file for the PWA.';

/**
* Execute the console command.
*/
public function handle(): void
{
try {
$defaultManifest = [
'name' => 'Laravel PWA',
'short_name' => 'LPT',
'background_color' => '#000000',
'display' => 'fullscreen',
'description' => 'A Progressive Web Application setup for Laravel projects.',
'theme_color' => '#000000',
'icons' => [
[
'src' => 'logo.png',
'sizes' => '512x512',
'type' => 'image/png',
],
],
];

// Load custom manifest from config, fallback to default
$manifest = Config::get('pwa.manifest', $defaultManifest);

if (empty($manifest['icons'])) {
$this->error('Manifest is missing icons. Aborting operation.');

return;
}

unset($manifest['start_url']);
$icons = $manifest['icons'];
unset($manifest['icons']);

$arrayMergeManifest = array_merge($manifest, ['start_url' => '/'], ['icons' => $icons]);

$jsonData = json_encode($arrayMergeManifest, JSON_PRETTY_PRINT);
if ($jsonData === false) {
$this->error('Failed to encode manifest array to JSON. Aborting operation.');

return;
}

$jsonData = str_replace('\/', '/', $jsonData);

$filePath = public_path('manifest.json');
if (! File::isWritable(public_path())) {
$this->error('Public directory is not writable. Check file permissions.');

return;
}

File::put($filePath, $jsonData);

$this->info('Manifest JSON updated successfully ✔');
} catch (\Exception $e) {
// Catch any errors and display an error message
$this->error('An error occurred while updating the manifest: '.$e->getMessage());
}
}
}
66 changes: 66 additions & 0 deletions src/Commands/PwaPublishCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace EragLaravelPwa\Commands;

use Illuminate\Console\Command;

class PwaPublishCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'erag:publish-laravel-pwa';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Publish Service Worker Manifest File for a Laravel PWA Application';

/**
* Execute the console command.
*/
public function handle(): void
{
// Step 1: Publish the pwa-config
$this->call('vendor:publish', [
'--tag' => 'erag:publish-pwa-config',
'--force' => true,
]);
$this->info('manifest.json file is published ✔');

// Step 2: Publish the manifest
$this->call('vendor:publish', [
'--tag' => 'erag:publish-manifest',
'--force' => true,
]);
$this->info('manifest.json file is published ✔');

// Step 3: Publish the offline page
$this->call('vendor:publish', [
'--tag' => 'erag:publish-offline',
'--force' => true,
]);
$this->info('offline.html file is published ✔');

// Step 4: Publish the sw js
$this->call('vendor:publish', [
'--tag' => 'erag:publish-sw',
'--force' => true,
]);
$this->info('sw.js file is published ✔');

// Step 5: Publish the logo
$this->call('vendor:publish', [
'--tag' => 'erag:publish-logo',
'--force' => true,
]);
$this->info('logo is published ✔');

$this->info('Greeting!.. Enjoy Laravel PWA 🎉');

}
}
63 changes: 63 additions & 0 deletions src/EragLaravelPwaServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace EragLaravelPwa;

use EragLaravelPwa\Commands\PWACommand;
use EragLaravelPwa\Commands\PwaPublishCommand;
use EragLaravelPwa\Services\PWAService;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class EragLaravelPwaServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
$this->app->singleton(PWAService::class, function ($app) {
return new PWAService;
});

$this->commands([
PwaPublishCommand::class,
PWACommand::class,
]);

$this->publishes([
__DIR__.'/Stubs/pwa.stub' => config_path('pwa.php'),
], 'erag:publish-pwa-config');

$this->publishes([
__DIR__.'/Stubs/manifest.stub' => public_path('manifest.json'),
], 'erag:publish-manifest');

$this->publishes([
__DIR__.'/Stubs/offline.stub' => public_path('offline.html'),
], 'erag:publish-offline');

$this->publishes([
__DIR__.'/Stubs/sw.stub' => public_path('sw.js'),
], 'erag:publish-sw');

$this->publishes([
__DIR__.'/Stubs/logo.png' => public_path('logo.png'),
], 'erag:publish-logo');

}

/**
* Bootstrap services.
*/
public function boot(): void
{

Blade::directive('PwaHead', function () {
return '<?php echo app(\\EragLaravelPwa\\Services\\PWAService::class)->headTag(); ?>';
});

Blade::directive('RegisterServiceWorkerScript', function () {
return '<?php echo app(\\EragLaravelPwa\\Services\\PWAService::class)->registerServiceWorkerScript(); ?>';
});
}
}
8 changes: 8 additions & 0 deletions src/Pwahelpers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

if (! function_exists('pwa')) {
function pwa()
{
return app('pwa');
}
}
94 changes: 94 additions & 0 deletions src/Services/PWAService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

namespace EragLaravelPwa\Services;

class PWAService
{
public function HeadTag(): string
{
$manifest = asset('/manifest.json');
$themeColor = config('pwa.manifest.theme_color', '#6777ef');
$icon = asset(config('pwa.manifest.icons.src', 'logo.png'));
$installButton = config('pwa.install-button', false);

$style = self::getInstallButtonStyle($installButton);

return <<<HTML
<!-- PWA -->
<meta name="theme-color" content="{$themeColor}"/>
<link rel="apple-touch-icon" href="{$icon}">
<link rel="manifest" href="{$manifest}">
<!-- PWA end -->
{$style}
HTML;
}

public function RegisterServiceWorkerScript(): string
{
$swPath = asset('/sw.js');
$isDebug = config('pwa.debug', false);
$consoleLog = $isDebug ? 'console.log' : '//';
$icon = asset(config('pwa.manifest.icons.src', 'logo.png'));
$installButton = config('pwa.install-button', false);

$installApp = self::getInstallAppHtml($installButton, $icon);
$installButtonJs = $installButton ? self::installButtonJs() : '';

return <<<HTML
{$installApp}
<!-- PWA scripts -->
<script src="{$swPath}"></script>
<script>
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js").then(
(registration) => {
{$consoleLog}("Service worker registration succeeded:");
},
(error) => {
{$consoleLog}("Service worker registration failed", error);
}
);
} else {
{$consoleLog}("Service workers are not supported.");
}
{$installButtonJs}
</script>
<!-- PWA scripts -->
HTML;
}

private static function installButtonJs(): string
{
return <<<'HTML'
let deferredPrompt;function showInstallPromotion(){document.getElementById("install-prompt").style.display="block"}window.addEventListener("load",(()=>{if(window.matchMedia("(display-mode: standalone)").matches){document.getElementById("install-prompt").style.display="none"}})),window.addEventListener("beforeinstallprompt",(e=>{e.preventDefault(),deferredPrompt=e,showInstallPromotion();document.getElementById("install-button").addEventListener("click",(()=>{deferredPrompt.prompt(),deferredPrompt.userChoice.then((e=>{deferredPrompt=null}))}))})),window.addEventListener("appinstalled",(()=>{document.getElementById("install-prompt").style.display="none"}));
HTML;
}

private static function getInstallButtonStyle(bool $installButton): string
{
if ($installButton) {
return <<<'HTML'
<style>
.box-icon{position:fixed;bottom:100px;right:100px}.box-icon .circle{cursor:pointer;width:60px;height:60px;background-color:rgba(255,150,35,0.2);border-radius:100%;position:absolute;top:-10px;left:-10px;transition:transform ease-out 0.1s,background 0.2s}.box-icon .circle:after{position:absolute;width:100%;height:100%;border-radius:50%;content:'';top:0;left:0;z-index:-1;animation:shadow-pulse 1s infinite;box-shadow:0 0 0 0 rgb(193 54 1 / 40%)}@keyframes shadow-pulse{0%{box-shadow:0 0 0 0 rgb(240,240,240)}100%{box-shadow:0 0 0 35px rgba(0,0,0,0)}}@keyframes shadow-pulse-big{0%{box-shadow:0 0 0 0 rgb(240,240,240)}100%{box-shadow:0 0 0 70px rgba(0,0,0,0)}}
</style>
HTML;
}

return '';
}

private static function getInstallAppHtml(bool $installButton, string $icon): string
{
if ($installButton) {
return <<<HTML
<div id="install-prompt" class="box-icon" style="display: none;">
<span id="install-button" class="circle">
<img src="{$icon}" alt="Install App">
</span>
</div>
HTML;
}

return '';
}
}
Binary file added src/Stubs/.DS_Store
Binary file not shown.
Binary file added src/Stubs/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions src/Stubs/manifest.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "Laravel PWA",
"short_name": "LPT",
"start_url": "/",
"background_color": "#000000",
"description": "A Progressive Web Application setup for Laravel projects.",
"display": "fullscreen",
"theme_color": "#000000",
"icons": [
{
"src": "logo.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
Loading

0 comments on commit b6d6adf

Please sign in to comment.