generated from boboko/starter
contact page, legal pages and category page
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Lunar\Models\Collection;
|
||||
use Lunar\Models\Product;
|
||||
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
public function show(string $locale, Collection $collection)
|
||||
{
|
||||
$products = $collection
|
||||
->products()
|
||||
->with(['variants.prices.currency', 'media'])
|
||||
->paginate(12)
|
||||
->withQueryString()
|
||||
->through(fn (Product $product) => [
|
||||
'name' => $product->translateAttribute('name'),
|
||||
'price' => $product->variants->first()?->prices->first()?->price->decimal,
|
||||
'image' => $product->media->first()?->getUrl(),
|
||||
'href' => route('product.show', ['product' => $product]),
|
||||
]);
|
||||
|
||||
return view('category.show', [
|
||||
'collection' => $collection,
|
||||
'products' => $products,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
public function index(string $locale)
|
||||
{
|
||||
return view('contact');
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,19 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\StoicPage;
|
||||
use Lunar\Models\Product;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function index()
|
||||
public function index(string $locale)
|
||||
{
|
||||
$page = StoicPage::firstWhere('slug', 'home');
|
||||
|
||||
if (! $page) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$products = Product::with(['variants.prices.currency', 'media'])
|
||||
->inRandomOrder()
|
||||
->limit(13)
|
||||
@@ -20,6 +27,7 @@ public function index()
|
||||
]);
|
||||
|
||||
return view('home', [
|
||||
'page' => $page,
|
||||
'heroProducts' => $products->take(5)->values(),
|
||||
'classicsProducts' => $products->slice(5)->values(),
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\StoicPage;
|
||||
|
||||
class LegalPageController extends Controller
|
||||
{
|
||||
public function terms(string $locale)
|
||||
{
|
||||
return $this->show('terms-and-conditions');
|
||||
}
|
||||
|
||||
public function shippingReturns(string $locale)
|
||||
{
|
||||
return $this->show('shipping-returns');
|
||||
}
|
||||
|
||||
public function privacy(string $locale)
|
||||
{
|
||||
return $this->show('privacy-policy');
|
||||
}
|
||||
|
||||
public function cookies(string $locale)
|
||||
{
|
||||
return $this->show('cookies-policy');
|
||||
}
|
||||
|
||||
private function show(string $slug)
|
||||
{
|
||||
$page = StoicPage::firstWhere('slug', $slug);
|
||||
|
||||
if (! $page) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
return view('legal', ['page' => $page]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use JacobJoergensen\LaravelPaper\Attributes\ContentPath;
|
||||
use JacobJoergensen\LaravelPaper\Attributes\Driver;
|
||||
use JacobJoergensen\LaravelPaper\Attributes\Timestamps;
|
||||
use JacobJoergensen\LaravelPaper\Paper;
|
||||
|
||||
#[Driver("markdown")]
|
||||
#[ContentPath("resources/stoic/content/pages")]
|
||||
#[Timestamps]
|
||||
class StoicPage extends Model
|
||||
{
|
||||
use Paper;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class Stoic
|
||||
{
|
||||
public static array $config = [];
|
||||
public static array $presets = [];
|
||||
public static string $thumbs_path;
|
||||
|
||||
private static function loadConfig(): void
|
||||
{
|
||||
if (!empty(static::$config)) {
|
||||
return;
|
||||
}
|
||||
$config = Yaml::parseFile(resource_path("stoic/stoic_config.yml"));
|
||||
static::$config = $config;
|
||||
static::$thumbs_path = $config["thumbs_path"];
|
||||
static::$presets = $config["presets"];
|
||||
}
|
||||
|
||||
public static function presets(): array
|
||||
{
|
||||
static::loadConfig();
|
||||
return static::$presets;
|
||||
}
|
||||
|
||||
// Returns the public URL for a stoic image at a given preset.
|
||||
public static function image(string $filename, string $preset): string
|
||||
{
|
||||
static::loadConfig();
|
||||
|
||||
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
|
||||
if ($ext === "svg") {
|
||||
$rel = static::thumbsRelPath() . "images/" . $filename;
|
||||
return Storage::disk("public")->url($rel);
|
||||
}
|
||||
|
||||
$webp = substr($filename, 0, -strlen($ext)) . "webp";
|
||||
$rel = static::thumbsRelPath() . "presets/" . $preset . "/" . $webp;
|
||||
|
||||
return Storage::disk("public")->url($rel);
|
||||
}
|
||||
|
||||
// Generates the full srcset string for all configured presets.
|
||||
public static function srcset(string $filename): string
|
||||
{
|
||||
static::loadConfig();
|
||||
|
||||
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
if ($ext === "svg") {
|
||||
return "";
|
||||
}
|
||||
|
||||
return collect(static::$presets)
|
||||
->map(
|
||||
fn($p) => static::image($filename, $p["code"]) .
|
||||
" " .
|
||||
$p["width"] .
|
||||
"w",
|
||||
)
|
||||
->implode(", ");
|
||||
}
|
||||
|
||||
// Returns [width, height] for a given preset from the sidecar JSON.
|
||||
public static function dimensions(string $filename, string $preset): array
|
||||
{
|
||||
static::loadConfig();
|
||||
|
||||
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
if ($ext === "svg") {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
$rel = static::thumbsRelPath() . "images/" . $filename . ".json";
|
||||
$path = Storage::disk("public")->path($rel);
|
||||
$meta = json_decode(@file_get_contents($path), true);
|
||||
|
||||
$p = $meta["presets"][$preset] ?? null;
|
||||
if (!$p) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
return [(int) $p["w"], (int) $p["h"]];
|
||||
}
|
||||
|
||||
// Path of the thumbs directory relative to the public storage disk root.
|
||||
// Uses a fixed marker so it works regardless of the app's base path (local vs Docker).
|
||||
private static function thumbsRelPath(): string
|
||||
{
|
||||
$marker = "/storage/app/public/";
|
||||
$pos = strpos(static::$thumbs_path, $marker);
|
||||
|
||||
if ($pos !== false) {
|
||||
return substr(static::$thumbs_path, $pos + strlen($marker));
|
||||
}
|
||||
|
||||
return ltrim(static::$thumbs_path, "/");
|
||||
}
|
||||
|
||||
public static function token(string $email): string
|
||||
{
|
||||
$ttl = 60;
|
||||
$payload = base64_encode(
|
||||
json_encode([
|
||||
"email" => $email,
|
||||
"exp" => time() + $ttl,
|
||||
]),
|
||||
);
|
||||
|
||||
$sig = hash_hmac(
|
||||
"sha256",
|
||||
$payload,
|
||||
config("services.stoic.sso_secret"),
|
||||
);
|
||||
|
||||
$token = "t=" . urlencode($payload) . "&s=" . $sig;
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public static function hasMany(
|
||||
string $relation,
|
||||
array $slugs,
|
||||
string $prefix,
|
||||
) {
|
||||
$slugs = array_map(
|
||||
fn($i) => str_replace($prefix . "/", "", $i),
|
||||
$slugs,
|
||||
);
|
||||
|
||||
$entries = $relation::whereIn("slug", $slugs)->get();
|
||||
|
||||
return collect(array_map(
|
||||
fn($i) => $entries->firstWhere("slug", $i),
|
||||
$slugs
|
||||
));
|
||||
}
|
||||
|
||||
public static function hasOne(
|
||||
string $relation,
|
||||
string $slug,
|
||||
string $prefix,
|
||||
) {
|
||||
$slug = str_replace($prefix . "/", "", $slug);
|
||||
return $relation::firstWhere("slug", $slug);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user