setup for stoic settings, changes in legal pages to use core's store details and contact page to show contact info next to form

This commit is contained in:
elvira
2026-09-28 17:09:08 +03:00
parent 4634e14924
commit ca362f81c8
22 changed files with 489 additions and 102 deletions
+7 -1
View File
@@ -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
+36 -1
View File
@@ -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,
));
}
}
+13
View File
@@ -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');
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace App\Services;
use Spatie\YamlFrontMatter\YamlFrontMatter;
/**
* Site-wide, marketing-editable settings from Stoic's `settings` singleton
* (resources/stoic/content/settings.md). Read directly rather than through a
* Paper model: Paper models map to a folder of entries, and this is one file
* at the content root. Legal and transactional details (address, ΑΦΜ, phone)
* live in boboko-core's StoreDetails instead.
*
* Bound as scoped in AppServiceProvider, so the file is parsed once per
* request (or queued job) and edits in Stoic show up on the next one.
*/
class StoicSettings
{
private const SOCIALS = [
'facebook' => '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<array{icon: string, label: string, url: string}>
*/
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;
}
}
+2 -2
View File
@@ -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"
Generated
+220 -64
View File
@@ -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",
+16
View File
@@ -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",
+1 -1
View File
@@ -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"
}
}
@@ -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
@@ -13,8 +13,8 @@ ## 1. Γενικά
Το ηλεκτρονικό κατάστημα 3DEALER (εφεξής «το Κατάστημα» ή «3DEALER») λειτουργεί από την επιχείρηση 3DEALER, με έδρα στην Πάρου 31, Κυψέλη, ΤΚ 11255, Αθήνα.
**ΑΦΜ:** @TODO
**ΓΕΜΗ:** @TODO
**ΑΦΜ:** {store_tax_identifier}
**ΓΕΜΗ:** {store_registration_number}
Για οποιαδήποτε πληροφορία ή επικοινωνία σχετικά με παραγγελίες, προϊόντα ή τη λειτουργία του Καταστήματος, μπορείτε να επικοινωνείτε μαζί μας:
+6
View File
@@ -0,0 +1,6 @@
---
meta_description: ""
facebook_url: ""
instagram_url: ""
tiktok_url: ""
---
+17
View File
@@ -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
@@ -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))
<address {{ $attributes->merge(['class' => 'not-italic']) }}>
<dl class="flex flex-col gap-10">
@if (filled($address))
<div class="flex flex-col gap-1">
<dt class="font-display text-sm font-semibold uppercase">{{ __('storefront.contact.address') }}</dt>
<dd class="font-display text-h4 font-semibold leading-tight">{{ $address }}</dd>
</div>
@endif
@if (filled($phone))
<div class="flex flex-col gap-1">
<dt class="font-display text-sm font-semibold uppercase">{{ __('storefront.contact.phone') }}</dt>
<dd class="font-display text-h4 font-semibold leading-tight">
<a href="tel:{{ preg_replace('/[^\d+]/', '', $phone) }}" class="underline-slide [--slide-h:1px] pb-0">{{ $phone }}</a>
</dd>
</div>
@endif
@if (filled($email))
<div class="flex flex-col gap-1">
<dt class="font-display text-sm font-semibold uppercase">Email</dt>
<dd class="font-display text-h4 font-semibold leading-tight break-all">
<a href="mailto:{{ $email }}" class="underline-slide [--slide-h:1px] pb-0">{{ $email }}</a>
</dd>
</div>
@endif
</dl>
</address>
@endif
+14 -23
View File
@@ -26,29 +26,20 @@
</div>
</div>
{{-- Social media --}}
<nav aria-label="Social media">
<ul class="flex items-center gap-4">
<li>
<a href="#" aria-label="Facebook" class="hover:text-brand">
<x-ui.icon name="facebook" :size="22" color="text-neutral-300" />
{{-- <span class="leading-none text-[22px] font-extrabold italic group-hover:underline">FB.</span> --}}
</a>
</li>
<li>
<a href="#" aria-label="Instagram" class="hover:text-brand">
<x-ui.icon name="instagram" :size="22" />
{{-- <span class="leading-none text-[22px] font-extrabold italic group-hover:underline">IG.</span> --}}
</a>
</li>
<li>
<a href="#" aria-label="TikTok" class="hover:text-brand">
<x-ui.icon name="tiktok" :size="22" />
{{-- <span class="leading-none text-[22px] font-extrabold italic group-hover:underline">TT.</span> --}}
</a>
</li>
</ul>
</nav>
{{-- Social media — URLs from Stoic (settings.md); empty ones are hidden. --}}
@if ($stoicSettings->socialLinks())
<nav aria-label="Social media">
<ul class="flex items-center gap-4">
@foreach ($stoicSettings->socialLinks() as $social)
<li>
<a href="{{ $social['url'] }}" aria-label="{{ $social['label'] }}" class="hover:text-brand">
<x-ui.icon :name="$social['icon']" :size="22" />
</a>
</li>
@endforeach
</ul>
</nav>
@endif
{{-- Copyright --}}
<div class="flex items-center gap-2">
+5 -3
View File
@@ -18,14 +18,14 @@
<path d="m88.4 0 4 28.9 29.7-5.2-14.3 25.7L135 62l-27.2 12.6 14.3 25.7-29.7-5.2-4 28.9-20.9-21.1L46.6 124l-4-28.9-29.7 5.2 14.3-25.7L0 62l27.2-12.6-14.3-25.7 29.7 5.2 4-28.9 20.9 21.1L88.4 0z"/>
</svg>
<h1 class="font-display text-h2 font-semibold leading-tight lg:text-h2"
<h1 class="font-display text-h1 font-semibold leading-tight"
data-controller="appear"
data-appear-visible-class="is-visible">
<span class="text-dance">Επικοινώνησε</span><br>
μαζί μας <span class="text-dance [--dance-delay:200ms]">άμεσα</span>
</h1>
<p class="max-w-md ">
<p class="max-w-xl ">
Έχεις απορία, ιδέα ή θες να μας πεις κάτι; Γράψε μας το μήνυμά σου και θα σου απαντήσουμε το συντομότερο δυνατό.
</p>
@@ -75,7 +75,9 @@ class="h-captcha min-h-[78px]"
</div>
<div class="min-h-[320px] bg-neutral-400 lg:min-h-full" aria-hidden="true"></div>
<div class="flex flex-col justify-center border-t border-black px-8 py-16 lg:border-t-0 lg:px-16">
<x-contact-details :store="$store" :email="$contactEmail" />
</div>
</section>
+14
View File
@@ -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 @@
<tr>
<td class="email-footer" align="center" style="padding:24px 24px 40px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:13px;line-height:1.6;color:#7a7a7a;">
@yield('footer')
@if ($stoicSettings->socialLinks())
<p style="margin:12px 0 0;">
@foreach ($stoicSettings->socialLinks() as $social)
@unless ($loop->first)&nbsp;&middot;&nbsp;@endunless<a href="{{ $social['url'] }}" target="_blank" style="color:#7a7a7a;text-decoration:underline;">{{ $social['label'] }}</a>
@endforeach
</p>
@endif
<p style="margin:12px 0 0;">
<a href="{{ url('/') }}" style="color:#7a7a7a;text-decoration:underline;">3dealer.gr</a>
&nbsp;&middot;&nbsp;&copy; {{ date('Y') }} 3Dealer
+15
View File
@@ -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')
<script type="application/ld+json">
{!! json_encode(array_filter([
'@context' => 'https://schema.org',
'@type' => 'Organization',
'name' => app(\Modules\Core\Store\Services\StoreDetailsService::class)->current()->translate('name') ?: config('app.name'),
'url' => url('/'),
'logo' => asset('images/logo.png'),
'sameAs' => array_column($stoicSettings->socialLinks(), 'url'),
]), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_TAG) !!}
</script>
@endpush
@section('content')
<div class="border-b border-black">
+3 -1
View File
@@ -14,7 +14,9 @@
<link rel="manifest" href="/site.webmanifest" />
<title>@yield('title', config('app.name'))</title>
<meta name="description" content="@yield('description', '')">
{{-- 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"). --}}
<meta name="description" content="{{ trim($__env->yieldContent('description')) ?: $stoicSettings->get('meta_description', '') }}">
{{-- Reciprocal hreflang: self-reference + every alternate locale + x-default --}}
@isset($currentLocale)
+1 -1
View File
@@ -20,7 +20,7 @@
</div>
<div class="legal-content" data-stoic="pages/{{ $page->slug }}#body">
{!! Str::markdown($page->content ?? '') !!}
{!! Str::markdown($content) !!}
</div>
</section>
+2
View File
@@ -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
@@ -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 @@
])
</div>
@if ($bankTransferInstructions)
<div class="email-rich" style="margin:0 0 40px;padding:20px;border:1px solid #000000;{{ $font }}font-size:15px;line-height:1.6;color:#000000;">
{!! $bankTransferInstructions !!}
</div>
@endif
{{-- Items --}}
@include('emails.partials.section-heading', ['text' => 'Προϊόντα'])
-1
View File
@@ -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',
);