-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f552237
commit b6d6adf
Showing
14 changed files
with
498 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 🎉'); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); ?>'; | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?php | ||
|
||
if (! function_exists('pwa')) { | ||
function pwa() | ||
{ | ||
return app('pwa'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
] | ||
} |
Oops, something went wrong.