diff --git a/app/Http/Controllers/ContactController.php b/app/Http/Controllers/ContactController.php index bcb5ca4..1ebcb73 100644 --- a/app/Http/Controllers/ContactController.php +++ b/app/Http/Controllers/ContactController.php @@ -10,6 +10,7 @@ use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\RateLimiter; use Illuminate\View\View; +use Modules\Core\Store\Services\StoreDetailsService; use Throwable; /** @@ -27,7 +28,12 @@ class ContactController extends Controller public function index(string $locale): View { - return view('contact'); + // Address and phone come from Store Details; the email is still + // CONTACT_EMAIL until Store Details has an email field. + return view('contact', [ + 'store' => app(StoreDetailsService::class)->current(), + 'contactEmail' => config('services.contact.email'), + ]); } public function send(string $locale, ContactRequest $request): RedirectResponse diff --git a/app/Http/Controllers/LegalPageController.php b/app/Http/Controllers/LegalPageController.php index cb2a270..ce69624 100644 --- a/app/Http/Controllers/LegalPageController.php +++ b/app/Http/Controllers/LegalPageController.php @@ -3,9 +3,26 @@ namespace App\Http\Controllers; use App\Models\StoicPage; +use Modules\Core\Store\Services\StoreDetailsService; class LegalPageController extends Controller { + /** + * {placeholder} => StoreDetails column, usable in the Stoic legal page + * markdown. + */ + private const PLACEHOLDERS = [ + '{store_name}' => 'name', + '{store_address}' => 'address', + '{store_phone}' => 'phone', + '{store_tax_identifier}' => 'tax_identifier', + '{store_registration_number}' => 'registration_number', + ]; + + public function __construct( + private readonly StoreDetailsService $storeDetails, + ) {} + public function terms(string $locale) { return $this->show('terms-and-conditions'); @@ -34,6 +51,24 @@ private function show(string $slug) abort(404); } - return view('legal', ['page' => $page]); + return view('legal', [ + 'page' => $page, + 'content' => $this->fillPlaceholders($page->content ?? ''), + ]); + } + + /** + * Swapped in before the markdown is rendered, so values are escaped: the + * rendered markdown is printed unescaped. An empty field renders as + * nothing rather than leaving the raw placeholder on the page. + */ + private function fillPlaceholders(string $content): string + { + $details = $this->storeDetails->current(); + + return strtr($content, array_map( + fn (string $column) => e((string) ($details->translate($column) ?? '')), + self::PLACEHOLDERS, + )); } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index c31fa40..8c57336 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,7 @@ use App\Models\Customer; use App\Models\Staff; +use App\Services\StoicSettings; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\View; @@ -17,6 +18,11 @@ class AppServiceProvider extends ServiceProvider { + public function register(): void + { + $this->app->scoped(StoicSettings::class); + } + public function boot(): void { Telemetry::optOut(); @@ -32,6 +38,13 @@ public function boot(): void )->items()); }); + // Site-wide settings edited in Stoic (settings.md): default meta + // description, social links for the footer, emails and schema.org. + View::composer( + ['layouts.app', 'components.footer', 'emails.layout', 'home'], + fn (ViewInstance $view) => $view->with('stoicSettings', app(StoicSettings::class)), + ); + if ($this->app->environment('production')) { URL::forceScheme('https'); } diff --git a/app/Services/StoicSettings.php b/app/Services/StoicSettings.php new file mode 100644 index 0000000..71f2b48 --- /dev/null +++ b/app/Services/StoicSettings.php @@ -0,0 +1,58 @@ + 'Facebook', + 'instagram' => 'Instagram', + 'tiktok' => 'TikTok', + ]; + + private array $data; + + public function __construct() + { + $path = resource_path('stoic/content/settings.md'); + + $this->data = is_file($path) + ? YamlFrontMatter::parse(file_get_contents($path))->matter() + : []; + } + + public function get(string $key, mixed $default = null): mixed + { + return filled($this->data[$key] ?? null) ? $this->data[$key] : $default; + } + + /** + * Only the networks that have a URL set, in display order. + * + * @return list + */ + public function socialLinks(): array + { + $links = []; + + foreach (self::SOCIALS as $icon => $label) { + if ($url = $this->get("{$icon}_url")) { + $links[] = ['icon' => $icon, 'label' => $label, 'url' => $url]; + } + } + + return $links; + } +} diff --git a/composer.json b/composer.json index 5b812cc..032ebb5 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "Tests\\": "tests/" } }, - "repositories": [ + "_repositories": [ { "type": "path", "url": "../boboko-core", @@ -41,7 +41,7 @@ } } ], - "_repositories": [ + "repositories": [ { "type": "vcs", "url": "https://code.radical-elements.com/boboko/core.git" diff --git a/composer.lock b/composer.lock index fb12a96..5f5b309 100644 --- a/composer.lock +++ b/composer.lock @@ -515,11 +515,11 @@ }, { "name": "boboko/core", - "version": "0.22.0", + "version": "0.26.1", "dist": { "type": "path", "url": "../boboko-core", - "reference": "547f07f01e043206d36b54290633f9f8fe6c1e14" + "reference": "569eb310e917b4d926262e9aa75440bff16f14d6" }, "require": { "laravel/framework": "^12.0", @@ -561,7 +561,9 @@ "Modules\\Core\\Providers\\FileServiceProvider", "Modules\\Core\\Providers\\ShippingServiceProvider", "Modules\\Core\\Providers\\OrderServiceProvider", - "Modules\\Core\\Providers\\PrivacyServiceProvider" + "Modules\\Core\\Providers\\PrivacyServiceProvider", + "Modules\\Core\\Providers\\WishlistServiceProvider", + "Modules\\Core\\Providers\\StoreServiceProvider" ] } }, @@ -938,6 +940,151 @@ ], "time": "2023-12-20T15:40:13+00:00" }, + { + "name": "composer/class-map-generator", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/composer/class-map-generator.git", + "reference": "c0efbeb2f3fd7e23c7f180a59765c0b48a31fbc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/c0efbeb2f3fd7e23c7f180a59765c0b48a31fbc4", + "reference": "c0efbeb2f3fd7e23c7f180a59765c0b48a31fbc4", + "shasum": "" + }, + "require": { + "composer/pcre": "^2.1 || ^3.1", + "php": "^7.2 || ^8.0", + "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7 || ^8" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6 || ^7 || ^8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\ClassMapGenerator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Utilities to scan PHP code and generate class maps.", + "keywords": [ + "classmap" + ], + "support": { + "issues": "https://github.com/composer/class-map-generator/issues", + "source": "https://github.com/composer/class-map-generator/tree/1.8.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2026-09-25T15:24:19+00:00" + }, + { + "name": "composer/pcre", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<2.2.2" + }, + "require-dev": { + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.4.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2026-06-07T11:47:49+00:00" + }, { "name": "composer/semver", "version": "3.5.0", @@ -1696,16 +1843,16 @@ }, { "name": "filament/actions", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/actions.git", - "reference": "1eb39ac07f06302262cf6f5d77927bff1ed626fb" + "reference": "ff79ce562cd774665531202c9c78549dc4fa922c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/actions/zipball/1eb39ac07f06302262cf6f5d77927bff1ed626fb", - "reference": "1eb39ac07f06302262cf6f5d77927bff1ed626fb", + "url": "https://api.github.com/repos/filamentphp/actions/zipball/ff79ce562cd774665531202c9c78549dc4fa922c", + "reference": "ff79ce562cd774665531202c9c78549dc4fa922c", "shasum": "" }, "require": { @@ -1741,20 +1888,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-15T16:56:16+00:00" + "time": "2026-09-26T19:38:45+00:00" }, { "name": "filament/filament", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/panels.git", - "reference": "1215d7d79b5609f66c1e432933610eefa0ab3ad6" + "reference": "e0f5272ee6f75f64dc831a8ac5ed05e31fa55436" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/panels/zipball/1215d7d79b5609f66c1e432933610eefa0ab3ad6", - "reference": "1215d7d79b5609f66c1e432933610eefa0ab3ad6", + "url": "https://api.github.com/repos/filamentphp/panels/zipball/e0f5272ee6f75f64dc831a8ac5ed05e31fa55436", + "reference": "e0f5272ee6f75f64dc831a8ac5ed05e31fa55436", "shasum": "" }, "require": { @@ -1799,20 +1946,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-20T19:15:07+00:00" + "time": "2026-09-26T19:39:41+00:00" }, { "name": "filament/forms", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/forms.git", - "reference": "10d7ba430544ae706a406713105ba37b18f52008" + "reference": "10c084a854bf6b9962717b8c21e12c579a8e9127" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/forms/zipball/10d7ba430544ae706a406713105ba37b18f52008", - "reference": "10d7ba430544ae706a406713105ba37b18f52008", + "url": "https://api.github.com/repos/filamentphp/forms/zipball/10c084a854bf6b9962717b8c21e12c579a8e9127", + "reference": "10c084a854bf6b9962717b8c21e12c579a8e9127", "shasum": "" }, "require": { @@ -1823,6 +1970,9 @@ "php": "^8.2", "ueberdosis/tiptap-php": "^2.0" }, + "suggest": { + "fakerphp/faker": "Required to generate fake rich content and Markdown." + }, "type": "library", "extra": { "laravel": { @@ -1849,11 +1999,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-20T18:45:30+00:00" + "time": "2026-09-26T19:39:08+00:00" }, { "name": "filament/infolists", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/infolists.git", @@ -1898,7 +2048,7 @@ }, { "name": "filament/notifications", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/notifications.git", @@ -1945,7 +2095,7 @@ }, { "name": "filament/query-builder", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/query-builder.git", @@ -1991,16 +2141,16 @@ }, { "name": "filament/schemas", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/schemas.git", - "reference": "dc4eeb57671b104b9e60f6d3f435f803c705e6df" + "reference": "fdb14a2cab2ffd2f7c6d8eef4593a4a4ed2c25ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/schemas/zipball/dc4eeb57671b104b9e60f6d3f435f803c705e6df", - "reference": "dc4eeb57671b104b9e60f6d3f435f803c705e6df", + "url": "https://api.github.com/repos/filamentphp/schemas/zipball/fdb14a2cab2ffd2f7c6d8eef4593a4a4ed2c25ba", + "reference": "fdb14a2cab2ffd2f7c6d8eef4593a4a4ed2c25ba", "shasum": "" }, "require": { @@ -2032,11 +2182,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-20T18:49:21+00:00" + "time": "2026-09-26T19:39:19+00:00" }, { "name": "filament/spatie-laravel-media-library-plugin", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-media-library-plugin.git", @@ -2073,27 +2223,28 @@ }, { "name": "filament/support", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/support.git", - "reference": "6bd7bdb5f5ff3b1a70cac6dabe28f5d996a36bcc" + "reference": "8468fa804bb8eed56ae7a86b2648822ec26e0476" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/support/zipball/6bd7bdb5f5ff3b1a70cac6dabe28f5d996a36bcc", - "reference": "6bd7bdb5f5ff3b1a70cac6dabe28f5d996a36bcc", + "url": "https://api.github.com/repos/filamentphp/support/zipball/8468fa804bb8eed56ae7a86b2648822ec26e0476", + "reference": "8468fa804bb8eed56ae7a86b2648822ec26e0476", "shasum": "" }, "require": { "blade-ui-kit/blade-heroicons": "^2.5", "composer-runtime-api": "^2.1", + "composer/class-map-generator": "^1.6", "danharrin/livewire-rate-limiting": "^2.0", "ext-intl": "*", "illuminate/contracts": "^11.28|^12.0|^13.0", "kirschbaum-development/eloquent-power-joins": "^4.0", "league/uri-components": "^7.0", - "livewire/livewire": "^3.7", + "livewire/livewire": "^3.8.6", "nette/php-generator": "^4.0", "php": "^8.2", "ryangjchandler/blade-capture-directive": "^1.0", @@ -2128,20 +2279,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-20T19:14:52+00:00" + "time": "2026-09-26T19:38:44+00:00" }, { "name": "filament/tables", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/tables.git", - "reference": "8a0c6634d752e0b71ed0871f92d533c0d03d7601" + "reference": "420ca362362a0a5059706b7c850b01706d27f6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/tables/zipball/8a0c6634d752e0b71ed0871f92d533c0d03d7601", - "reference": "8a0c6634d752e0b71ed0871f92d533c0d03d7601", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/420ca362362a0a5059706b7c850b01706d27f6b6", + "reference": "420ca362362a0a5059706b7c850b01706d27f6b6", "shasum": "" }, "require": { @@ -2174,11 +2325,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-20T18:53:09+00:00" + "time": "2026-09-26T19:39:27+00:00" }, { "name": "filament/widgets", - "version": "v4.13.4", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/filamentphp/widgets.git", @@ -5155,16 +5306,16 @@ }, { "name": "nesbot/carbon", - "version": "3.14.0", + "version": "3.14.1", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "0023eaa2c9110e47446dd512a263c69c40cd41f2" + "reference": "34e9109535165bf1d7ff17a610492372ae73a896" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/0023eaa2c9110e47446dd512a263c69c40cd41f2", - "reference": "0023eaa2c9110e47446dd512a263c69c40cd41f2", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/34e9109535165bf1d7ff17a610492372ae73a896", + "reference": "34e9109535165bf1d7ff17a610492372ae73a896", "shasum": "" }, "require": { @@ -5256,7 +5407,7 @@ "type": "tidelift" } ], - "time": "2026-09-12T20:45:19+00:00" + "time": "2026-09-27T12:07:26+00:00" }, { "name": "nette/php-generator", @@ -6807,20 +6958,25 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + "reference": "ee15a5a2022c8383906b225055e9496a6a5e6e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/ee15a5a2022c8383906b225055e9496a6a5e6e3b", + "reference": "ee15a5a2022c8383906b225055e9496a6a5e6e3b", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.25" }, "type": "library", "extra": { @@ -6844,7 +7000,7 @@ } ], "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", + "homepage": "https://www.phpdoc.org", "keywords": [ "FQSEN", "phpDocumentor", @@ -6854,9 +7010,9 @@ ], "support": { "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.2.1" }, - "time": "2020-06-27T09:03:43+00:00" + "time": "2025-11-10T21:21:55+00:00" }, { "name": "phpdocumentor/reflection-docblock", @@ -7058,16 +7214,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.5", + "version": "2.3.6", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "148cefffaf0233e4c08cc13db8a195a56dd6dfe9" + "reference": "1427af4647235b4a73b13940b1f1258d3584f36e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/148cefffaf0233e4c08cc13db8a195a56dd6dfe9", - "reference": "148cefffaf0233e4c08cc13db8a195a56dd6dfe9", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1427af4647235b4a73b13940b1f1258d3584f36e", + "reference": "1427af4647235b4a73b13940b1f1258d3584f36e", "shasum": "" }, "require": { @@ -7099,9 +7255,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.5" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.6" }, - "time": "2026-08-31T16:05:28+00:00" + "time": "2026-09-27T20:07:45+00:00" }, { "name": "pragmarx/google2fa", @@ -8852,16 +9008,16 @@ }, { "name": "spatie/laravel-package-tools", - "version": "1.93.2", + "version": "1.93.3", "source": { "type": "git", "url": "https://github.com/spatie/laravel-package-tools.git", - "reference": "e927d5b5b05e9fecae098e559e51918aa608ad02" + "reference": "7aeef26bd8d4909bec744dbf47aee7d1395588c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/e927d5b5b05e9fecae098e559e51918aa608ad02", - "reference": "e927d5b5b05e9fecae098e559e51918aa608ad02", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/7aeef26bd8d4909bec744dbf47aee7d1395588c1", + "reference": "7aeef26bd8d4909bec744dbf47aee7d1395588c1", "shasum": "" }, "require": { @@ -8901,7 +9057,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-package-tools/issues", - "source": "https://github.com/spatie/laravel-package-tools/tree/1.93.2" + "source": "https://github.com/spatie/laravel-package-tools/tree/1.93.3" }, "funding": [ { @@ -8909,7 +9065,7 @@ "type": "github" } ], - "time": "2026-08-26T09:13:25+00:00" + "time": "2026-09-28T07:16:50+00:00" }, { "name": "spatie/laravel-permission", diff --git a/package-lock.json b/package-lock.json index 5f554c4..9a40908 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "dependencies": { + "@boboko/core": "file:../boboko-core", "@hotwired/stimulus": "^3.2.2", "@hotwired/turbo": "^8.0.23", "axios": "^1.15.2", @@ -18,6 +19,21 @@ "vite": "^8.0.0" } }, + "../boboko-core": { + "name": "@boboko/core", + "version": "0.26.1", + "dependencies": { + "@hotwired/stimulus": "^3.2.2", + "leaflet": "^1.9.4" + }, + "peerDependencies": { + "vite": "^8.0.0" + } + }, + "node_modules/@boboko/core": { + "resolved": "../boboko-core", + "link": true + }, "node_modules/@emnapi/core": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", diff --git a/package.json b/package.json index 383a932..373ee7a 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,6 @@ }, "_comment_boboko_core": "Mirrors composer.json's repositories/_repositories toggle: swap @boboko/core above with the line in _dependencies below (and back) by hand to switch between the local path-repo checkout and a tagged VCS install. The #semver:0.x range mirrors composer.json's own \"boboko/core\": \"0.*\" constraint exactly — note ^0.23.0 would NOT be equivalent here, since npm's caret locks the minor version too below 1.0.0 (>=0.23.0 <0.24.0). 0.x matches any 0.y.z tag, same as Composer's 0.*. npm reads the repo's git tags, filters to valid semver ones, and resolves the best match, so `npm update @boboko/core` alone picks up a newly pushed tag within range, no manual edit here per release. See docker/entrypoint-vite.sh and CONTRIBUTE.md.", "_dependencies": { - "@boboko/core": "file:../boboko-core" + "@boboko/core": "file:../boboko-core" } } diff --git a/resources/stoic/content/pages/privacy-policy.md b/resources/stoic/content/pages/privacy-policy.md index 9f1488e..f78b175 100644 --- a/resources/stoic/content/pages/privacy-policy.md +++ b/resources/stoic/content/pages/privacy-policy.md @@ -20,8 +20,8 @@ ## 1. Υπεύθυνος επεξεργασίας **3DEALER** Πάρου 31, Κυψέλη, ΤΚ 11255, Αθήνα -ΑΦΜ: @TODO -ΓΕΜΗ: @TODO +ΑΦΜ: {store_tax_identifier} +ΓΕΜΗ: {store_registration_number} Email: [print@3dealer.gr](mailto:print@3dealer.gr) Τηλέφωνο: 6976 443140 diff --git a/resources/stoic/content/pages/terms-and-conditions.md b/resources/stoic/content/pages/terms-and-conditions.md index 7d66a1b..a3714bf 100644 --- a/resources/stoic/content/pages/terms-and-conditions.md +++ b/resources/stoic/content/pages/terms-and-conditions.md @@ -13,8 +13,8 @@ ## 1. Γενικά Το ηλεκτρονικό κατάστημα 3DEALER (εφεξής «το Κατάστημα» ή «3DEALER») λειτουργεί από την επιχείρηση 3DEALER, με έδρα στην Πάρου 31, Κυψέλη, ΤΚ 11255, Αθήνα. -**ΑΦΜ:** @TODO -**ΓΕΜΗ:** @TODO +**ΑΦΜ:** {store_tax_identifier} +**ΓΕΜΗ:** {store_registration_number} Για οποιαδήποτε πληροφορία ή επικοινωνία σχετικά με παραγγελίες, προϊόντα ή τη λειτουργία του Καταστήματος, μπορείτε να επικοινωνείτε μαζί μας: diff --git a/resources/stoic/content/settings.md b/resources/stoic/content/settings.md new file mode 100644 index 0000000..3cad19e --- /dev/null +++ b/resources/stoic/content/settings.md @@ -0,0 +1,6 @@ +--- +meta_description: "" +facebook_url: "" +instagram_url: "" +tiktok_url: "" +--- diff --git a/resources/stoic/stoic_schemas.yml b/resources/stoic/stoic_schemas.yml index 5954658..ce27f45 100644 --- a/resources/stoic/stoic_schemas.yml +++ b/resources/stoic/stoic_schemas.yml @@ -131,3 +131,20 @@ schemas: - name: body label: Body ui: markdown + - name: settings + label: Settings + type: singleton + file: settings.md + fields: + - name: meta_description + label: "Default Meta Description (used when a page has none)" + ui: text + - name: facebook_url + label: Facebook URL + ui: string + - name: instagram_url + label: Instagram URL + ui: string + - name: tiktok_url + label: TikTok URL + ui: string diff --git a/resources/views/components/contact-details.blade.php b/resources/views/components/contact-details.blade.php new file mode 100644 index 0000000..6cc14cc --- /dev/null +++ b/resources/views/components/contact-details.blade.php @@ -0,0 +1,45 @@ +{{-- + Store address and phone from Lunar's Store Details (Modules\Core\Store), + email from CONTACT_EMAIL until Store Details has an email field too. + Each line is left out when its value is empty. +--}} +@props([ + 'store' => null, + 'email' => null, +]) + +@php + $address = $store?->translate('address'); + $phone = $store?->phone; +@endphp + +@if (filled($address) || filled($phone) || filled($email)) +
merge(['class' => 'not-italic']) }}> +
+ @if (filled($address)) +
+
{{ __('storefront.contact.address') }}
+
{{ $address }}
+
+ @endif + + @if (filled($phone)) +
+
{{ __('storefront.contact.phone') }}
+
+ {{ $phone }} +
+
+ @endif + + @if (filled($email)) +
+
Email
+
+ {{ $email }} +
+
+ @endif +
+
+@endif diff --git a/resources/views/components/footer.blade.php b/resources/views/components/footer.blade.php index 974dc28..0c79fc1 100644 --- a/resources/views/components/footer.blade.php +++ b/resources/views/components/footer.blade.php @@ -26,29 +26,20 @@ - {{-- Social media --}} - + {{-- Social media — URLs from Stoic (settings.md); empty ones are hidden. --}} + @if ($stoicSettings->socialLinks()) + + @endif {{-- Copyright --}}
diff --git a/resources/views/contact.blade.php b/resources/views/contact.blade.php index 17d04df..3545a17 100644 --- a/resources/views/contact.blade.php +++ b/resources/views/contact.blade.php @@ -18,14 +18,14 @@ -

Επικοινώνησε
μαζί μας άμεσα

-

+

Έχεις απορία, ιδέα ή θες να μας πεις κάτι; Γράψε μας το μήνυμά σου και θα σου απαντήσουμε το συντομότερο δυνατό.

@@ -75,7 +75,9 @@ class="h-captcha min-h-[78px]"
- +
+ +
diff --git a/resources/views/emails/layout.blade.php b/resources/views/emails/layout.blade.php index 670d1b0..d187b0f 100644 --- a/resources/views/emails/layout.blade.php +++ b/resources/views/emails/layout.blade.php @@ -42,6 +42,13 @@ #MessageViewBody, #MessageWebViewDiv { width: 100% !important; } u + #email-body a { color: inherit; text-decoration: none; } + /* Admin-authored rich text (e.g. bank transfer instructions). */ + .email-rich p, .email-rich ul, .email-rich ol, .email-rich table { margin: 0 0 12px; } + .email-rich > :last-child { margin-bottom: 0; } + .email-rich a { color: #000000; text-decoration: underline; } + .email-rich table { width: 100%; border-collapse: collapse; } + .email-rich th, .email-rich td { padding: 6px 8px; border: 1px solid #e5e5e5; text-align: left; vertical-align: top; } + @media only screen and (max-width: 480px) { .email-container { width: 100% !important; max-width: 100% !important; } .email-header { padding: 24px 20px 12px !important; } @@ -83,6 +90,13 @@ @yield('footer') + @if ($stoicSettings->socialLinks()) +

+ @foreach ($stoicSettings->socialLinks() as $social) + @unless ($loop->first) · @endunless{{ $social['label'] }} + @endforeach +

+ @endif

3dealer.gr  · © {{ date('Y') }} 3Dealer diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index 26008e0..8e5d1ff 100644 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -3,6 +3,21 @@ @section('title', $page->meta_title) @section('description', $page->meta_description) +{{-- Organization structured data, home page only. Name from core's StoreDetails, + social profiles (sameAs) from Stoic settings.md. --}} +@push('seo') + +@endpush + @section('content')

diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 8d26cc9..4288fda 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -14,7 +14,9 @@ @yield('title', config('app.name')) - + {{-- Falls back to Stoic's default when a page sets none, or sets it to an + empty meta_description (@yield's own default only covers "not set"). --}} + {{-- Reciprocal hreflang: self-reference + every alternate locale + x-default --}} @isset($currentLocale) diff --git a/resources/views/legal.blade.php b/resources/views/legal.blade.php index 07262c9..65f1cfb 100644 --- a/resources/views/legal.blade.php +++ b/resources/views/legal.blade.php @@ -20,7 +20,7 @@
diff --git a/resources/views/product/show.blade.php b/resources/views/product/show.blade.php index f6d9cf9..284b7fd 100644 --- a/resources/views/product/show.blade.php +++ b/resources/views/product/show.blade.php @@ -281,6 +281,8 @@ class="mt-20" 'price' => $recommendation['price'], 'image' => $recommendation['image'], 'href' => route('product.show', ['id' => $recommendation['id']]), + 'variantId' => $recommendation['variant_id'] ?? null, + 'hasCustomFields' => $recommendation['has_custom_fields'] ?? false, ])->all()" /> @endif diff --git a/resources/views/vendor/core/order/notifications/placed.blade.php b/resources/views/vendor/core/order/notifications/placed.blade.php index fad63b4..557b06f 100644 --- a/resources/views/vendor/core/order/notifications/placed.blade.php +++ b/resources/views/vendor/core/order/notifications/placed.blade.php @@ -27,6 +27,10 @@ $email = $order->billingAddress?->contact_email ?? $order->shippingAddress?->contact_email; $comments = $order->shippingAddress?->delivery_instructions; + // Sanitized HTML from Store Details, only for bank transfer orders. + $bankTransferInstructions = app(\Modules\Core\Store\Services\StoreDetailsService::class) + ->bankTransferInstructionsFor($order, 'el'); + $muted = 'color:#5c5c5c;font-size:14px;'; $font = "font-family:'Manrope',Arial,Helvetica,sans-serif;"; @endphp @@ -53,6 +57,12 @@ ]) + @if ($bankTransferInstructions) +
+ {!! $bankTransferInstructions !!} +
+ @endif + {{-- Items --}} @include('emails.partials.section-heading', ['text' => 'Προϊόντα']) diff --git a/routes/web.php b/routes/web.php index 99b0a7d..1b5e543 100644 --- a/routes/web.php +++ b/routes/web.php @@ -63,7 +63,6 @@ Route::get('/contact', [ContactController::class, 'index'])->name('contact'); Route::post('/contact', [ContactController::class, 'send'])->name('contact.send'); - Route::get('/terms-and-conditions', [LegalPageController::class, 'terms'])->name( 'legal.terms', );