Add (lqip)

This commit is contained in:
2023-07-30 16:59:30 +08:00
parent 3acbf03d4e
commit 3812976c0f
22 changed files with 166 additions and 85 deletions

View File

@@ -41,4 +41,4 @@ public function handle()
SitemapGenerator::create(config('app.url')) SitemapGenerator::create(config('app.url'))
->writeToFile(public_path('sitemap.xml')); ->writeToFile(public_path('sitemap.xml'));
} }
} }

View File

@@ -40,6 +40,6 @@ public function __construct()
public function redirectTo() public function redirectTo()
{ {
return route('posts.manage'); return route('posts.manage');
} }
} }

View File

@@ -6,26 +6,23 @@
use App\Models\Category; use App\Models\Category;
use App\Models\CountryLocale; use App\Models\CountryLocale;
use App\Models\Post; use App\Models\Post;
use Illuminate\Http\Request;
use Artesaos\SEOTools\Facades\SEOTools;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\JsonLd;
use Artesaos\SEOTools\Facades\JsonLdMulti; use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\SEOTools;
use Illuminate\Http\Request;
class HomeController extends Controller class HomeController extends Controller
{ {
public function index(Request $request) public function index(Request $request)
{ {
SEOTools::metatags(); SEOTools::metatags();
SEOTools::twitter(); SEOTools::twitter();
SEOTools::opengraph(); SEOTools::opengraph();
SEOTools::jsonLd(); SEOTools::jsonLd();
SEOTools::setTitle("Top Product Reviews, Deals & New Launches"); SEOTools::setTitle('Top Product Reviews, Deals & New Launches');
SEOTools::setDescription("Explore ProductAlert for in-depth product reviews and incredible deals. We cover Beauty, Tech, Home Appliances, Health & Fitness, Parenting, and more."); SEOTools::setDescription('Explore ProductAlert for in-depth product reviews and incredible deals. We cover Beauty, Tech, Home Appliances, Health & Fitness, Parenting, and more.');
$country = strtolower($request->session()->get('country')); $country = strtolower($request->session()->get('country'));
@@ -35,7 +32,6 @@ public function index(Request $request)
public function country(Request $request, $country) public function country(Request $request, $country)
{ {
$country_locale = CountryLocale::where('slug', $country)->first(); $country_locale = CountryLocale::where('slug', $country)->first();
if (! is_null($country_locale)) { if (! is_null($country_locale)) {
@@ -67,7 +63,6 @@ public function country(Request $request, $country)
->take(10) ->take(10)
->get(); ->get();
SEOTools::metatags(); SEOTools::metatags();
SEOTools::twitter(); SEOTools::twitter();
SEOTools::opengraph(); SEOTools::opengraph();
@@ -111,19 +106,18 @@ public function countryCategory(Request $request, $country, $category)
->distinct() ->distinct()
->paginate(15); ->paginate(15);
SEOTools::metatags(); SEOTools::metatags();
SEOTools::twitter(); SEOTools::twitter();
SEOTools::opengraph(); SEOTools::opengraph();
SEOTools::jsonLd(); SEOTools::jsonLd();
$country_name = get_country_name_by_iso($country_locale->country_iso); $country_name = get_country_name_by_iso($country_locale->country_iso);
SEOTools::setTitle("Top {$category->name} Reviews in {$country_name}"); SEOTools::setTitle("Top {$category->name} Reviews in {$country_name}");
$category_name = strtolower($category->name); $category_name = strtolower($category->name);
SEOTools::setDescription("Stay updated with the latest {$category_name} product launches in {$country_name}. Find in-depth reviews and exciting deals with ProductAlert, your guide to {$category_name} shopping.");
SEOTools::setDescription("Stay updated with the latest {$category_name} product launches in {$country_name}. Find in-depth reviews and exciting deals with ProductAlert, your guide to {$category_name} shopping.");
return view('front.country_category', compact('country_locale', 'category', 'latest_posts')); return view('front.country_category', compact('country_locale', 'category', 'latest_posts'));
} }
@@ -143,16 +137,16 @@ public function all(Request $request, $country)
->distinct() ->distinct()
->paginate(15); ->paginate(15);
SEOTools::metatags(); SEOTools::metatags();
SEOTools::twitter(); SEOTools::twitter();
SEOTools::opengraph(); SEOTools::opengraph();
SEOTools::jsonLd(); SEOTools::jsonLd();
$country_name = get_country_name_by_iso($country_locale->country_iso); $country_name = get_country_name_by_iso($country_locale->country_iso);
SEOTools::setTitle("Find Product Reviews and Best Deals for {$country_name}"); SEOTools::setTitle("Find Product Reviews and Best Deals for {$country_name}");
SEOTools::setDescription("Discover the latest product reviews and unbeatable deals at ProductAlert, your guide to shopping in {$country_name}. Stay on top of fresh product updates."); SEOTools::setDescription("Discover the latest product reviews and unbeatable deals at ProductAlert, your guide to shopping in {$country_name}. Stay on top of fresh product updates.");
return view('front.country_all', compact('country_locale', 'latest_posts')); return view('front.country_all', compact('country_locale', 'latest_posts'));
} }
@@ -163,31 +157,29 @@ public function post(Request $request, $country, $post_slug)
if (! is_null($post)) { if (! is_null($post)) {
SEOMeta::setTitle($post->title);
SEOMeta::setDescription($post->excerpt);
SEOMeta::addMeta('article:published_time', $post->publish_date, 'property');
SEOMeta::addMeta('article:section', $post->post_category->category->name, 'property');
SEOMeta::setTitle($post->title); OpenGraph::setDescription($post->excerpt);
SEOMeta::setDescription($post->excerpt); OpenGraph::setTitle($post->title);
SEOMeta::addMeta('article:published_time', $post->publish_date, 'property'); OpenGraph::setUrl(url()->current());
SEOMeta::addMeta('article:section', $post->post_category->category->name, 'property'); OpenGraph::addProperty('type', 'article');
OpenGraph::addProperty('locale', $post->post_category->category->country_locale->i18n);
OpenGraph::addImage($post->featured_image);
OpenGraph::setDescription($post->excerpt); $jsonld_multi = JsonLdMulti::newJsonLd();
OpenGraph::setTitle($post->title); $jsonld_multi->setTitle($post->title)
OpenGraph::setUrl(url()->current()); ->setDescription($post->excerpt)
OpenGraph::addProperty('type', 'article'); ->setType('Article')
OpenGraph::addProperty('locale', $post->post_category->category->country_locale->i18n); ->addImage($post->featured_image)
OpenGraph::addImage($post->featured_image); ->addValue('author', $post->author->name)
->addValue('datePublished', $post->publish_at)
$jsonld_multi = JsonLdMulti::newJsonLd(); ->addValue('dateCreated', $post->publish_at)
$jsonld_multi->setTitle($post->title) ->addValue('dateModified', $post->updated_at->format('Y-m-d'))
->setDescription($post->excerpt) ->addValue('description', $post->excerpt)
->setType('Article') ->addValue('articleBody', trim(preg_replace('/\s\s+/', ' ', strip_tags($post->html_body))));
->addImage($post->featured_image)
->addValue('author', $post->author->name)
->addValue('datePublished', $post->publish_at)
->addValue('dateCreated', $post->publish_at)
->addValue('dateModified', $post->updated_at->format('Y-m-d'))
->addValue('description', $post->excerpt)
->addValue('articleBody', trim(preg_replace('/\s\s+/', ' ', strip_tags($post->html_body))))
;
return view('front.post', compact('post')); return view('front.post', compact('post'));
} }

View File

@@ -87,4 +87,15 @@ public function getHtmlBodyAttribute()
return ''; return '';
} }
public function getFeaturedImageLqipAttribute()
{
$featuredImage = $this->featured_image;
// Get the extension of the original featured image
$extension = pathinfo($featuredImage, PATHINFO_EXTENSION);
// Append "_lqip" before the extension to create the LQIP image URL
return str_replace(".{$extension}", "_lqip.{$extension}", $featuredImage);
}
} }

View File

@@ -188,11 +188,11 @@
'aliases' => Facade::defaultAliases()->merge([ 'aliases' => Facade::defaultAliases()->merge([
// 'Example' => App\Facades\Example::class, // 'Example' => App\Facades\Example::class,
'Debugbar' => Barryvdh\Debugbar\Facades\Debugbar::class, 'Debugbar' => Barryvdh\Debugbar\Facades\Debugbar::class,
'SEOMeta' => Artesaos\SEOTools\Facades\SEOMeta::class, 'SEOMeta' => Artesaos\SEOTools\Facades\SEOMeta::class,
'OpenGraph' => Artesaos\SEOTools\Facades\OpenGraph::class, 'OpenGraph' => Artesaos\SEOTools\Facades\OpenGraph::class,
'Twitter' => Artesaos\SEOTools\Facades\TwitterCard::class, 'Twitter' => Artesaos\SEOTools\Facades\TwitterCard::class,
'JsonLd' => Artesaos\SEOTools\Facades\JsonLd::class, 'JsonLd' => Artesaos\SEOTools\Facades\JsonLd::class,
'JsonLdMulti' => Artesaos\SEOTools\Facades\JsonLdMulti::class, 'JsonLdMulti' => Artesaos\SEOTools\Facades\JsonLdMulti::class,
'SEO' => Artesaos\SEOTools\Facades\SEOTools::class, 'SEO' => Artesaos\SEOTools\Facades\SEOTools::class,
])->toArray(), ])->toArray(),

View File

@@ -6,7 +6,7 @@
* The Google Tag Manager id, should be a code that looks something like "gtm-xxxx". * The Google Tag Manager id, should be a code that looks something like "gtm-xxxx".
*/ */
'id' => env('GOOGLE_TAG_MANAGER_ID', ''), 'id' => env('GOOGLE_TAG_MANAGER_ID', ''),
/* /*
* Enable or disable script rendering. Useful for local development. * Enable or disable script rendering. Useful for local development.
*/ */

View File

@@ -9,7 +9,7 @@
* The default configurations to be used by the meta generator. * The default configurations to be used by the meta generator.
*/ */
'defaults' => [ 'defaults' => [
'title' => "ProductAlert", // set false to total remove 'title' => 'ProductAlert', // set false to total remove
'titleBefore' => false, // Put defaults.title before page title, like 'It's Over 9000! - Dashboard' 'titleBefore' => false, // Put defaults.title before page title, like 'It's Over 9000! - Dashboard'
'description' => 'Find top-rated product reviews at ProductAlert. Discover the latest trends, best brands, and right prices. Your guide to making the best purchase decisions!', // set false to total remove 'description' => 'Find top-rated product reviews at ProductAlert. Discover the latest trends, best brands, and right prices. Your guide to making the best purchase decisions!', // set false to total remove
'separator' => ' - ', 'separator' => ' - ',

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -98,7 +98,7 @@
"src": "resources/sass/admin-app.scss" "src": "resources/sass/admin-app.scss"
}, },
"resources/sass/front-app.scss": { "resources/sass/front-app.scss": {
"file": "assets/front-app-9bc7257c.css", "file": "assets/front-app-87d3f80a.css",
"isEntry": true, "isEntry": true,
"src": "resources/sass/front-app.scss" "src": "resources/sass/front-app.scss"
} }

Binary file not shown.

View File

@@ -0,0 +1,43 @@
.lqip-loader {
position: relative;
overflow: hidden;
width: auto;
}
.lqip-loader img {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.lqip-loader img,
.lqip-loader img {
display: block;
}
.lqip-loader img {
position: relative;
float: left;
display: block;
}
.lqip-frozen {
-webkit-filter: blur(8px);
-moz-filter: blur(8px);
-o-filter: blur(8px);
-ms-filter: blur(8px);
filter: blur(8px);
transform: scale(1.04);
animation: 0.2s ease-in 0.4s 1 forwards lqipFade;
width: 100%;
}
@keyframes lqipFade {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}

View File

@@ -3,3 +3,5 @@
@import "~bootstrap/scss/bootstrap"; @import "~bootstrap/scss/bootstrap";
@import "~/bootstrap-icons/font/bootstrap-icons.css"; @import "~/bootstrap-icons/font/bootstrap-icons.css";
@import "../css/front-app.css";

View File

@@ -22,7 +22,14 @@
<a href="{{ route('home.country.post', ['country' => $country_locale->country_iso, 'post_slug' => $post->slug]) }}" <a href="{{ route('home.country.post', ['country' => $country_locale->country_iso, 'post_slug' => $post->slug]) }}"
class="text-decoration-none"> class="text-decoration-none">
<div class="card-img-top ratio ratio-16x9"> <div class="card-img-top ratio ratio-16x9">
<img src="{{ $post->featured_image }}" alt="Photo of {{ $post->title }}"> <div class="lqip-loader">
<!-- Use the LQIP image with the appropriate URL -->
<img src="{{ $post->featured_image }}" alt="Photo of {{ $post->name }}">
<!-- Use the final JPEG image with the appropriate URL -->
<img class="lqip-frozen" src="{{ $post->featured_image_lqip }}" alt="Placeholder image of {{ $post->name }}">
</div>
</div> </div>
</a> </a>
@@ -78,8 +85,13 @@ class="text-decoration-none">{{ $post->title }}</a>
<a href="{{ route('home.country.post', ['country' => $country_locale->country_iso, 'post_slug' => $post->slug]) }}" <a href="{{ route('home.country.post', ['country' => $country_locale->country_iso, 'post_slug' => $post->slug]) }}"
class="text-decoration-none"> class="text-decoration-none">
<div class="img-fluid rounded-start ratio ratio-16x9"> <div class="img-fluid rounded-start ratio ratio-16x9">
<img src="{{ $post->featured_image }}" <div class="lqip-loader">
alt="Photo of {{ $post->title }}"> <!-- Use the LQIP image with the appropriate URL -->
<img src="{{ $post->featured_image }}" alt="Photo of {{ $post->name }}">
<!-- Use the final JPEG image with the appropriate URL -->
<img class="lqip-frozen" src="{{ $post->featured_image_lqip }}" alt="Placeholder image of {{ $post->name }}">
</div>
</div> </div>
</a> </a>
</div> </div>

View File

@@ -44,9 +44,15 @@
</div> </div>
<a class="card-img-top" <a class="card-img-top"
href="{{ route('home.country.post', ['country' => $country_locale->country_iso, 'post_slug' => $post->slug]) }}"> href="{{ route('home.country.post', ['country' => $country_locale->country_iso, 'post_slug' => $post->slug]) }}">
<img src="{{ $post->featured_image }}" <div class="img-fluid rounded-start ratio ratio-16x9">
class="card-img-top rounded-bottom-2 rounded-top-0" <div class="lqip-loader">
alt="Photo of {{ $post->title }}"> <!-- Use the LQIP image with the appropriate URL -->
<img src="{{ $post->featured_image }}" alt="Photo of {{ $post->name }}">
<!-- Use the final JPEG image with the appropriate URL -->
<img class="lqip-frozen" src="{{ $post->featured_image_lqip }}" alt="Placeholder image of {{ $post->name }}">
</div>
</div>
</a> </a>
</div> </div>

View File

@@ -43,9 +43,15 @@
</div> </div>
<a class="card-img-top" <a class="card-img-top"
href="{{ route('home.country.post', ['country' => $country_locale->country_iso, 'post_slug' => $post->slug]) }}"> href="{{ route('home.country.post', ['country' => $country_locale->country_iso, 'post_slug' => $post->slug]) }}">
<img src="{{ $post->featured_image }}" <div class="img-fluid rounded-start ratio ratio-16x9">
class="card-img-top rounded-bottom-2 rounded-top-0" <div class="lqip-loader">
alt="Photo of {{ $post->title }}"> <!-- Use the LQIP image with the appropriate URL -->
<img src="{{ $post->featured_image }}" alt="Photo of {{ $post->name }}">
<!-- Use the final JPEG image with the appropriate URL -->
<img class="lqip-frozen" src="{{ $post->featured_image_lqip }}" alt="Placeholder image of {{ $post->name }}">
</div>
</div>
</a> </a>
</div> </div>

View File

@@ -31,7 +31,15 @@
<h2 class="h5">{{ $post->excerpt }}</h2> <h2 class="h5">{{ $post->excerpt }}</h2>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<img src="{{ $post->featured_image }}" alt="Photo of {{ $post->name }}" class="img-fluid rounded-3"> <div class="img-fluid rounded-start ratio ratio-16x9">
<div class="lqip-loader">
<!-- Use the LQIP image with the appropriate URL -->
<img class="img-fluid rounded-2" src="{{ $post->featured_image }}" alt="Photo of {{ $post->name }}">
<!-- Use the final JPEG image with the appropriate URL -->
<img class="lqip-frozen img-fluid rounded-2" src="{{ $post->featured_image_lqip }}" alt="Placeholder image of {{ $post->name }}">
</div>
</div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
{!! $post->html_body !!} {!! $post->html_body !!}

View File

@@ -1,9 +1,9 @@
<?php <?php
use App\Models\Post;
use App\Models\Author; use App\Models\Author;
use App\Models\Category; use App\Models\Category;
use App\Models\CountryLocale; use App\Models\CountryLocale;
use App\Models\Post;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
/* /*
@@ -30,7 +30,6 @@
})->name('api.admin.post.get'); })->name('api.admin.post.get');
Route::get('/country-locales', function () { Route::get('/country-locales', function () {
$country_locales = CountryLocale::where('enabled', true)->get(); $country_locales = CountryLocale::where('enabled', true)->get();
$default_locale_slug = 'my'; $default_locale_slug = 'my';

View File

@@ -1,4 +1,6 @@
#!/bin/bash #!/bin/bash
eval 'APP_URL=https://productalert.co php artisan ziggy:generate'; eval 'APP_URL=https://productalert.co php artisan ziggy:generate';
eval 'blade-formatter --write resources/\*_/_.blade.php';
eval './vendor/bin/pint';
eval 'npm run build'; eval 'npm run build';