feat: New design and optimization
This commit is contained in:
@@ -4,6 +4,9 @@ namespace App\Http\Controllers\Client;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Carousel;
|
||||
use App\Models\Faq;
|
||||
use App\Models\Product;
|
||||
use App\Models\Testimonial;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Storage;
|
||||
@@ -13,6 +16,7 @@ class HomeController extends Controller
|
||||
public function home()
|
||||
{
|
||||
$carousel = Carousel::all();
|
||||
$testimonail = Testimonial::all();
|
||||
|
||||
|
||||
$response = [
|
||||
@@ -21,6 +25,14 @@ class HomeController extends Controller
|
||||
"alt" => $item->alt,
|
||||
"image_url" => $item->image_url ? asset(Storage::url($item->image_url)) : null,
|
||||
];
|
||||
}),
|
||||
"testimonial" => $testimonail->map(function ($item) {
|
||||
return [
|
||||
"name" => $item->name,
|
||||
"location" => $item->location,
|
||||
"image" => $item->image ? asset(Storage::url($item->image)) : null,
|
||||
"description" => $item->description
|
||||
];
|
||||
})
|
||||
];
|
||||
return Inertia::render('welcome', ['data' => $response]);
|
||||
@@ -28,12 +40,39 @@ class HomeController extends Controller
|
||||
}
|
||||
public function product()
|
||||
{
|
||||
return Inertia::render('product');
|
||||
$product = Product::all();
|
||||
$productResponse = $product->map(function ($item) {
|
||||
return [
|
||||
"id" => $item->id,
|
||||
"title" => $item->title,
|
||||
"type" => $item->type,
|
||||
"image_url" => $item->image_url ? asset(Storage::url($item->image_url)) : null,
|
||||
];
|
||||
});
|
||||
return Inertia::render('product', ['product' => $productResponse]);
|
||||
}
|
||||
public function art()
|
||||
{
|
||||
return Inertia::render('art');
|
||||
}
|
||||
|
||||
public function bespoke()
|
||||
{
|
||||
$product = Product::where("type", "bespoke")->get();
|
||||
$productResponse = $product->map(function ($item) {
|
||||
return [
|
||||
"id" => $item->id,
|
||||
"title" => $item->title,
|
||||
"type" => $item->type,
|
||||
"image_url" => $item->image_url ? asset(Storage::url($item->image_url)) : null,
|
||||
];
|
||||
})->values();
|
||||
return Inertia::render("bespoke", ["product" => $productResponse]);
|
||||
}
|
||||
public function gallery()
|
||||
{
|
||||
return Inertia::render("gallery");
|
||||
}
|
||||
public function contact()
|
||||
{
|
||||
return Inertia::render('contact');
|
||||
|
||||
63
app/Http/Controllers/Client/ProductController.php
Normal file
63
app/Http/Controllers/Client/ProductController.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\client;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Storage;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$product = Product::all();
|
||||
$productResponse = $product->map(function ($item) {
|
||||
return [
|
||||
"id" => $item->id,
|
||||
"title" => $item->title,
|
||||
"type" => $item->type,
|
||||
"image_url" => $item->image_url ? asset(Storage::url($item->image_url)) : null,
|
||||
];
|
||||
});
|
||||
|
||||
return Inertia::render("dashboard/products/index", ['product' => $productResponse]);
|
||||
}
|
||||
|
||||
public function productAdd()
|
||||
{
|
||||
return Inertia::render("dashboard/products/add");
|
||||
}
|
||||
public function productAddPost(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
"title" => "required|string",
|
||||
"type" => "required|string",
|
||||
"image_url" => "file"
|
||||
]);
|
||||
|
||||
if ($request->hasFile('image_url')) {
|
||||
$path = $request->file('image_url')->store('product', 'public');
|
||||
|
||||
$product = Product::create([
|
||||
'title' => $validated['title'],
|
||||
"type" => $validated['type'],
|
||||
'image_url' => $path
|
||||
]);
|
||||
|
||||
$productResponse = [
|
||||
"title" => $product->title,
|
||||
"type" => $product->type,
|
||||
"image_url" => $product->image_url ? asset(Storage::url($product->image_url)) : null,
|
||||
];
|
||||
|
||||
return to_route('dashboard.product.index', $productResponse);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => 'File upload failed',
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
@@ -4,20 +4,57 @@ namespace App\Http\Controllers\Client;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\testimonialRequest;
|
||||
use App\Models\testimonial;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Spatie\LaravelImageOptimizer\Facades\ImageOptimizer;
|
||||
use Storage;
|
||||
|
||||
class TestimonialController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return Inertia::render('dashboard/testimonial');
|
||||
$testimonial = Testimonial::all();
|
||||
$testimonialResponse = $testimonial->map(function ($item) {
|
||||
return [
|
||||
"name" => $item->name,
|
||||
"description" => $item->description,
|
||||
"location" => $item->location,
|
||||
"image" => $item->image ? asset(Storage::url($item->image)) : null,
|
||||
];
|
||||
});
|
||||
|
||||
return Inertia::render('dashboard/testimonial', ["testimonial" => $testimonialResponse]);
|
||||
}
|
||||
|
||||
public function store(testimonialRequest $request)
|
||||
{
|
||||
$request->validated();
|
||||
|
||||
dd($request);
|
||||
if ($request->hasFile('image')) {
|
||||
$path = $request->file('image')->store('testimonial', 'public');
|
||||
$fullPath = storage_path('app/public/' . $path);
|
||||
ImageOptimizer::optimize($fullPath);
|
||||
|
||||
$testimonial = Testimonial::create([
|
||||
"name" => $request->name,
|
||||
"location" => $request->location,
|
||||
"description" => $request->description,
|
||||
"image" => $path
|
||||
]);
|
||||
|
||||
$testimonialResponse = [
|
||||
"name" => $testimonial->name,
|
||||
"location" => $testimonial->location,
|
||||
"description" => $testimonial->description,
|
||||
"image" => $testimonial->image ? asset(Storage::url($testimonial->image)) : null
|
||||
];
|
||||
|
||||
return to_route('home', $testimonialResponse);
|
||||
}
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => 'File upload failed',
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Inspiring;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Inertia\Middleware;
|
||||
|
||||
class HandleInertiaRequests extends Middleware
|
||||
@@ -38,6 +41,10 @@ class HandleInertiaRequests extends Middleware
|
||||
{
|
||||
[$message, $author] = str(Inspiring::quotes()->random())->explode('-');
|
||||
|
||||
$locale = Session::get('locale', 'en');
|
||||
App::setLocale($locale);
|
||||
|
||||
|
||||
return [
|
||||
...parent::share($request),
|
||||
'name' => config('app.name'),
|
||||
@@ -45,7 +52,9 @@ class HandleInertiaRequests extends Middleware
|
||||
'auth' => [
|
||||
'user' => $request->user(),
|
||||
],
|
||||
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
|
||||
'sidebarOpen' => !$request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
|
||||
'locale' => $locale,
|
||||
'translations' => trans("message")
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,9 @@ class testimonialRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string',
|
||||
'rating' => 'required|string',
|
||||
'company' => 'string',
|
||||
'post' => 'string',
|
||||
'location' => 'string',
|
||||
'description' => 'required|string'
|
||||
'description' => 'required|string',
|
||||
'image' => 'required|file'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
14
app/Models/Product.php
Normal file
14
app/Models/Product.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Product extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'image_url',
|
||||
'type',
|
||||
];
|
||||
}
|
||||
@@ -4,14 +4,12 @@ namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class testimonial extends Model
|
||||
class Testimonial extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'company',
|
||||
'post',
|
||||
'location',
|
||||
'rating',
|
||||
'description'
|
||||
'description',
|
||||
'image'
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -19,6 +22,18 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
Inertia::share([
|
||||
'locale' => function () {
|
||||
$locale = Session::get('locale', config('app.locale'));
|
||||
App::setLocale($locale);
|
||||
return $locale;
|
||||
},
|
||||
'translations' => function () {
|
||||
$locale = Session::get('locale', config('app.locale'));
|
||||
App::setLocale($locale);
|
||||
return trans('messages');
|
||||
},
|
||||
]);
|
||||
// App::setLocale(Session::get('locale', config('app.locale')));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@ use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
|
||||
use Spatie\LaravelImageOptimizer\Middlewares\OptimizeImages;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
web: __DIR__ . '/../routes/web.php',
|
||||
commands: __DIR__ . '/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
@@ -20,6 +21,7 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
HandleAppearance::class,
|
||||
HandleInertiaRequests::class,
|
||||
AddLinkHeadersForPreloadedAssets::class,
|
||||
OptimizeImages::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"laravel/fortify": "^1.30",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"laravel/wayfinder": "^0.1.9"
|
||||
"laravel/wayfinder": "^0.1.9",
|
||||
"spatie/laravel-image-optimizer": "^1.8",
|
||||
"spatie/laravel-sitemap": "^7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
@@ -83,4 +85,4 @@
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
}
|
||||
|
||||
708
composer.lock
generated
708
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "db1a607ff3200db016bc62d7a8dd6399",
|
||||
"content-hash": "380388e121fb1b22c0f87fe4161b2452",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@@ -2312,6 +2312,73 @@
|
||||
],
|
||||
"time": "2024-12-08T08:18:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Masterminds/html5-php.git",
|
||||
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
|
||||
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Masterminds\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matt Butcher",
|
||||
"email": "technosophos@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Matt Farina",
|
||||
"email": "matt@mattfarina.com"
|
||||
},
|
||||
{
|
||||
"name": "Asmir Mustafic",
|
||||
"email": "goetas@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An HTML5 parser and serializer.",
|
||||
"homepage": "http://masterminds.github.io/html5-php",
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"dom",
|
||||
"html",
|
||||
"parser",
|
||||
"querypath",
|
||||
"serializer",
|
||||
"xml"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||
"source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
|
||||
},
|
||||
"time": "2025-07-25T09:04:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "3.9.0",
|
||||
@@ -2671,6 +2738,60 @@
|
||||
},
|
||||
"time": "2025-08-06T21:43:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nicmart/tree",
|
||||
"version": "0.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nicmart/Tree.git",
|
||||
"reference": "f5e17bf18d78cfb0666ebb9f956c3acd8d14229d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nicmart/Tree/zipball/f5e17bf18d78cfb0666ebb9f956c3acd8d14229d",
|
||||
"reference": "f5e17bf18d78cfb0666ebb9f956c3acd8d14229d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ergebnis/composer-normalize": "^2.44.0",
|
||||
"ergebnis/license": "^2.6.0",
|
||||
"ergebnis/php-cs-fixer-config": "^6.28.1",
|
||||
"fakerphp/faker": "^1.24.1",
|
||||
"infection/infection": "~0.26.19",
|
||||
"phpunit/phpunit": "^9.6.19",
|
||||
"psalm/plugin-phpunit": "~0.19.0",
|
||||
"vimeo/psalm": "^5.26.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Tree\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolò Martini",
|
||||
"email": "nicmartnic@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Andreas Möller",
|
||||
"email": "am@localheinz.com"
|
||||
}
|
||||
],
|
||||
"description": "A basic but flexible php tree data structure and a fluent tree builder implementation.",
|
||||
"support": {
|
||||
"issues": "https://github.com/nicmart/Tree/issues",
|
||||
"source": "https://github.com/nicmart/Tree/tree/0.9.0"
|
||||
},
|
||||
"time": "2024-11-22T15:36:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.6.1",
|
||||
@@ -3816,6 +3937,520 @@
|
||||
},
|
||||
"time": "2025-09-04T20:59:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/browsershot",
|
||||
"version": "5.0.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/browsershot.git",
|
||||
"reference": "f84d9c332899596d0884922772593a10e3925969"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/browsershot/zipball/f84d9c332899596d0884922772593a10e3925969",
|
||||
"reference": "f84d9c332899596d0884922772593a10e3925969",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"ext-json": "*",
|
||||
"php": "^8.2",
|
||||
"spatie/temporary-directory": "^2.0",
|
||||
"symfony/process": "^6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"pestphp/pest": "^3.0",
|
||||
"spatie/image": "^3.6",
|
||||
"spatie/pdf-to-text": "^1.52",
|
||||
"spatie/phpunit-snapshot-assertions": "^4.2.3|^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\Browsershot\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://github.com/freekmurze",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Convert a webpage to an image or pdf using headless Chrome",
|
||||
"homepage": "https://github.com/spatie/browsershot",
|
||||
"keywords": [
|
||||
"chrome",
|
||||
"convert",
|
||||
"headless",
|
||||
"image",
|
||||
"pdf",
|
||||
"puppeteer",
|
||||
"screenshot",
|
||||
"webpage"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/spatie/browsershot/tree/5.0.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-10-08T07:40:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/crawler",
|
||||
"version": "8.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/crawler.git",
|
||||
"reference": "4f4c3ead439e7e57085c0b802bc4e5b44fb7d751"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/crawler/zipball/4f4c3ead439e7e57085c0b802bc4e5b44fb7d751",
|
||||
"reference": "4f4c3ead439e7e57085c0b802bc4e5b44fb7d751",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^7.3",
|
||||
"guzzlehttp/psr7": "^2.0",
|
||||
"illuminate/collections": "^10.0|^11.0|^12.0",
|
||||
"nicmart/tree": "^0.9",
|
||||
"php": "^8.2",
|
||||
"spatie/browsershot": "^5.0.5",
|
||||
"spatie/robots-txt": "^2.0",
|
||||
"symfony/dom-crawler": "^6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"pestphp/pest": "^2.0|^3.0",
|
||||
"spatie/ray": "^1.37"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\Crawler\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be"
|
||||
}
|
||||
],
|
||||
"description": "Crawl all internal links found on a website",
|
||||
"homepage": "https://github.com/spatie/crawler",
|
||||
"keywords": [
|
||||
"crawler",
|
||||
"link",
|
||||
"spatie",
|
||||
"website"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/crawler/issues",
|
||||
"source": "https://github.com/spatie/crawler/tree/8.4.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://spatie.be/open-source/support-us",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-05-20T09:00:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/image-optimizer",
|
||||
"version": "1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/image-optimizer.git",
|
||||
"reference": "4fd22035e81d98fffced65a8c20d9ec4daa9671c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/image-optimizer/zipball/4fd22035e81d98fffced65a8c20d9ec4daa9671c",
|
||||
"reference": "4fd22035e81d98fffced65a8c20d9ec4daa9671c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"php": "^7.3|^8.0",
|
||||
"psr/log": "^1.0 | ^2.0 | ^3.0",
|
||||
"symfony/process": "^4.2|^5.0|^6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"pestphp/pest": "^1.21",
|
||||
"phpunit/phpunit": "^8.5.21|^9.4.4",
|
||||
"symfony/var-dumper": "^4.2|^5.0|^6.0|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\ImageOptimizer\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Easily optimize images using PHP",
|
||||
"homepage": "https://github.com/spatie/image-optimizer",
|
||||
"keywords": [
|
||||
"image-optimizer",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/image-optimizer/issues",
|
||||
"source": "https://github.com/spatie/image-optimizer/tree/1.8.0"
|
||||
},
|
||||
"time": "2024-11-04T08:24:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-image-optimizer",
|
||||
"version": "1.8.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-image-optimizer.git",
|
||||
"reference": "6681a48097009bba1800f0215190816df22fe116"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-image-optimizer/zipball/6681a48097009bba1800f0215190816df22fe116",
|
||||
"reference": "6681a48097009bba1800f0215190816df22fe116",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"laravel/framework": "^8.0|^9.0|^10.0|^11.0|^12.0",
|
||||
"php": "^8.0",
|
||||
"spatie/image-optimizer": "^1.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0",
|
||||
"phpunit/phpunit": "^9.4|^10.5|^11.5.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"ImageOptimizer": "Spatie\\LaravelImageOptimizer\\Facades\\ImageOptimizer"
|
||||
},
|
||||
"providers": [
|
||||
"Spatie\\LaravelImageOptimizer\\ImageOptimizerServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\LaravelImageOptimizer\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Optimize images in your Laravel app",
|
||||
"homepage": "https://github.com/spatie/laravel-image-optimizer",
|
||||
"keywords": [
|
||||
"laravel-image-optimizer",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/spatie/laravel-image-optimizer/tree/1.8.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://spatie.be/open-source/support-us",
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-21T14:01:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
"version": "1.92.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-package-tools.git",
|
||||
"reference": "f09a799850b1ed765103a4f0b4355006360c49a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/f09a799850b1ed765103a4f0b4355006360c49a5",
|
||||
"reference": "f09a799850b1ed765103a4f0b4355006360c49a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "^9.28|^10.0|^11.0|^12.0",
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.5",
|
||||
"orchestra/testbench": "^7.7|^8.0|^9.0|^10.0",
|
||||
"pestphp/pest": "^1.23|^2.1|^3.1",
|
||||
"phpunit/php-code-coverage": "^9.0|^10.0|^11.0",
|
||||
"phpunit/phpunit": "^9.5.24|^10.5|^11.5",
|
||||
"spatie/pest-plugin-test-time": "^1.1|^2.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\LaravelPackageTools\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Tools for creating Laravel packages",
|
||||
"homepage": "https://github.com/spatie/laravel-package-tools",
|
||||
"keywords": [
|
||||
"laravel-package-tools",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-package-tools/issues",
|
||||
"source": "https://github.com/spatie/laravel-package-tools/tree/1.92.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-17T15:46:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-sitemap",
|
||||
"version": "7.3.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-sitemap.git",
|
||||
"reference": "077b36c64bc4f373f4d95a1ac6ee1c0624acfdd3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-sitemap/zipball/077b36c64bc4f373f4d95a1ac6ee1c0624acfdd3",
|
||||
"reference": "077b36c64bc4f373f4d95a1ac6ee1c0624acfdd3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"illuminate/support": "^11.0|^12.0",
|
||||
"nesbot/carbon": "^2.71|^3.0",
|
||||
"php": "^8.2||^8.3||^8.4",
|
||||
"spatie/crawler": "^8.0.1",
|
||||
"spatie/laravel-package-tools": "^1.16.1",
|
||||
"symfony/dom-crawler": "^6.3.4|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.6.6",
|
||||
"orchestra/testbench": "^9.0|^10.0",
|
||||
"pestphp/pest": "^3.7.4",
|
||||
"spatie/pest-plugin-snapshots": "^2.1",
|
||||
"spatie/phpunit-snapshot-assertions": "^5.1.2",
|
||||
"spatie/temporary-directory": "^2.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Spatie\\Sitemap\\SitemapServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\Sitemap\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Create and generate sitemaps with ease",
|
||||
"homepage": "https://github.com/spatie/laravel-sitemap",
|
||||
"keywords": [
|
||||
"laravel-sitemap",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/spatie/laravel-sitemap/tree/7.3.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://spatie.be/open-source/support-us",
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-25T08:07:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/robots-txt",
|
||||
"version": "2.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/robots-txt.git",
|
||||
"reference": "1b59dde3fd4e1b71967b40841369c6e9779282f3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/robots-txt/zipball/1b59dde3fd4e1b71967b40841369c6e9779282f3",
|
||||
"reference": "1b59dde3fd4e1b71967b40841369c6e9779282f3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^11.5.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\Robots\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Brent Roose",
|
||||
"email": "brent@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Determine if a page may be crawled from robots.txt and robots meta tags",
|
||||
"homepage": "https://github.com/spatie/robots-txt",
|
||||
"keywords": [
|
||||
"robots-txt",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/robots-txt/issues",
|
||||
"source": "https://github.com/spatie/robots-txt/tree/2.5.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://spatie.be/open-source/support-us",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-09-19T10:37:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/temporary-directory",
|
||||
"version": "2.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/temporary-directory.git",
|
||||
"reference": "580eddfe9a0a41a902cac6eeb8f066b42e65a32b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/temporary-directory/zipball/580eddfe9a0a41a902cac6eeb8f066b42e65a32b",
|
||||
"reference": "580eddfe9a0a41a902cac6eeb8f066b42e65a32b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\TemporaryDirectory\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Vanderbist",
|
||||
"email": "alex@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Easily create, use and destroy temporary directories",
|
||||
"homepage": "https://github.com/spatie/temporary-directory",
|
||||
"keywords": [
|
||||
"php",
|
||||
"spatie",
|
||||
"temporary-directory"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/temporary-directory/issues",
|
||||
"source": "https://github.com/spatie/temporary-directory/tree/2.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://spatie.be/open-source/support-us",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-01-13T13:04:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/clock",
|
||||
"version": "v7.3.0",
|
||||
@@ -4120,6 +4755,77 @@
|
||||
],
|
||||
"time": "2024-09-25T14:21:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v7.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/efa076ea0eeff504383ff0dcf827ea5ce15690ba",
|
||||
"reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"masterminds/html5": "^2.6",
|
||||
"php": ">=8.2",
|
||||
"symfony/polyfill-ctype": "~1.8",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/css-selector": "^6.4|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\DomCrawler\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Eases DOM navigation for HTML and XML documents",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/dom-crawler/tree/v7.3.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-06T20:13:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/error-handler",
|
||||
"version": "v7.3.2",
|
||||
|
||||
66
config/image-optimizer.php
Normal file
66
config/image-optimizer.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
use Spatie\ImageOptimizer\Optimizers\Cwebp;
|
||||
use Spatie\ImageOptimizer\Optimizers\Gifsicle;
|
||||
use Spatie\ImageOptimizer\Optimizers\Jpegoptim;
|
||||
use Spatie\ImageOptimizer\Optimizers\Optipng;
|
||||
use Spatie\ImageOptimizer\Optimizers\Pngquant;
|
||||
use Spatie\ImageOptimizer\Optimizers\Svgo;
|
||||
|
||||
return [
|
||||
/*
|
||||
* When calling `optimize` the package will automatically determine which optimizers
|
||||
* should run for the given image.
|
||||
*/
|
||||
'optimizers' => [
|
||||
|
||||
Jpegoptim::class => [
|
||||
'-m85', // set maximum quality to 85%
|
||||
'--strip-all', // this strips out all text information such as comments and EXIF data
|
||||
'--all-progressive', // this will make sure the resulting image is a progressive one
|
||||
],
|
||||
|
||||
Pngquant::class => [
|
||||
'--force', // required parameter for this package
|
||||
],
|
||||
|
||||
Optipng::class => [
|
||||
'-i0', // this will result in a non-interlaced, progressive scanned image
|
||||
'-o2', // this set the optimization level to two (multiple IDAT compression trials)
|
||||
'-quiet', // required parameter for this package
|
||||
],
|
||||
|
||||
Svgo::class => [
|
||||
'--disable=cleanupIDs', // disabling because it is know to cause troubles
|
||||
],
|
||||
|
||||
Gifsicle::class => [
|
||||
'-b', // required parameter for this package
|
||||
'-O3', // this produces the slowest but best results
|
||||
],
|
||||
|
||||
Cwebp::class => [
|
||||
'-m 6', // for the slowest compression method in order to get the best compression.
|
||||
'-pass 10', // for maximizing the amount of analysis pass.
|
||||
'-mt', // multithreading for some speed improvements.
|
||||
'-q 90', // quality factor that brings the least noticeable changes.
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
* The directory where your binaries are stored.
|
||||
* Only use this when you binaries are not accessible in the global environment.
|
||||
*/
|
||||
'binary_path' => '',
|
||||
|
||||
/*
|
||||
* The maximum time in seconds each optimizer is allowed to run separately.
|
||||
*/
|
||||
'timeout' => 60,
|
||||
|
||||
/*
|
||||
* If set to `true` all output of the optimizer binaries will be appended to the default log.
|
||||
* You can also set this to a class that implements `Psr\Log\LoggerInterface`.
|
||||
*/
|
||||
'log_optimizer_activity' => false,
|
||||
];
|
||||
57
config/sitemap.php
Normal file
57
config/sitemap.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use Spatie\Sitemap\Crawler\Profile;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
* These options will be passed to GuzzleHttp\Client when it is created.
|
||||
* For in-depth information on all options see the Guzzle docs:
|
||||
*
|
||||
* http://docs.guzzlephp.org/en/stable/request-options.html
|
||||
*/
|
||||
'guzzle_options' => [
|
||||
|
||||
/*
|
||||
* Whether or not cookies are used in a request.
|
||||
*/
|
||||
RequestOptions::COOKIES => true,
|
||||
|
||||
/*
|
||||
* The number of seconds to wait while trying to connect to a server.
|
||||
* Use 0 to wait indefinitely.
|
||||
*/
|
||||
RequestOptions::CONNECT_TIMEOUT => 10,
|
||||
|
||||
/*
|
||||
* The timeout of the request in seconds. Use 0 to wait indefinitely.
|
||||
*/
|
||||
RequestOptions::TIMEOUT => 10,
|
||||
|
||||
/*
|
||||
* Describes the redirect behavior of a request.
|
||||
*/
|
||||
RequestOptions::ALLOW_REDIRECTS => false,
|
||||
],
|
||||
|
||||
/*
|
||||
* The sitemap generator can execute JavaScript on each page so it will
|
||||
* discover links that are generated by your JS scripts. This feature
|
||||
* is powered by headless Chrome.
|
||||
*/
|
||||
'execute_javascript' => false,
|
||||
|
||||
/*
|
||||
* The package will make an educated guess as to where Google Chrome is installed.
|
||||
* You can also manually pass its location here.
|
||||
*/
|
||||
'chrome_binary_path' => null,
|
||||
|
||||
/*
|
||||
* The sitemap generator uses a CrawlProfile implementation to determine
|
||||
* which urls should be crawled for the sitemap.
|
||||
*/
|
||||
'crawl_profile' => Profile::class,
|
||||
|
||||
];
|
||||
@@ -13,10 +13,8 @@ return new class extends Migration {
|
||||
Schema::create('testimonials', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('company');
|
||||
$table->string('post');
|
||||
$table->string('location');
|
||||
$table->double('rating');
|
||||
$table->string("image");
|
||||
$table->text('description');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('products', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('image_url');
|
||||
$table->string('title');
|
||||
$table->string('type');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('products');
|
||||
}
|
||||
};
|
||||
BIN
public/favicon.png
Normal file
BIN
public/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
resources/assets/img/production/IMG_2719.jpg
Normal file
BIN
resources/assets/img/production/IMG_2719.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
BIN
resources/assets/img/products/sci trad 8.jpg
Normal file
BIN
resources/assets/img/products/sci trad 8.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 826 KiB |
@@ -187,3 +187,8 @@
|
||||
.filepond--credits {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#testimonial .swiper .swiper-pagination {
|
||||
position: relative;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export default function AppLogo() {
|
||||
</div>
|
||||
<div className="ml-1 grid flex-1 text-left text-sm">
|
||||
<span className="mb-0.5 truncate leading-tight font-semibold">
|
||||
Laravel Starter Kit
|
||||
Soorya Carpet
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { NavFooter } from '@/components/nav-footer';
|
||||
import { NavMain } from '@/components/nav-main';
|
||||
import { NavUser } from '@/components/nav-user';
|
||||
import {
|
||||
@@ -15,7 +14,12 @@ import dashboardcarousel from '@/routes/dashboard/carousel';
|
||||
import testimonial from '@/routes/testimonial';
|
||||
import { type NavItem } from '@/types';
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { BookOpen, Folder, GalleryHorizontal, LayoutGrid } from 'lucide-react';
|
||||
import {
|
||||
GalleryHorizontal,
|
||||
LayoutGrid,
|
||||
Package,
|
||||
TableOfContents,
|
||||
} from 'lucide-react';
|
||||
import AppLogo from './app-logo';
|
||||
|
||||
const mainNavItems: NavItem[] = [
|
||||
@@ -29,23 +33,20 @@ const mainNavItems: NavItem[] = [
|
||||
href: dashboardcarousel.index(),
|
||||
icon: GalleryHorizontal,
|
||||
},
|
||||
{
|
||||
title: 'Products',
|
||||
href: dashboard.product.index(),
|
||||
icon: Package,
|
||||
},
|
||||
{
|
||||
title: 'Testimonial',
|
||||
href: testimonial.index(),
|
||||
icon: GalleryHorizontal,
|
||||
},
|
||||
];
|
||||
|
||||
const footerNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Repository',
|
||||
href: 'https://github.com/laravel/react-starter-kit',
|
||||
icon: Folder,
|
||||
},
|
||||
{
|
||||
title: 'Documentation',
|
||||
href: 'https://laravel.com/docs/starter-kits#react',
|
||||
icon: BookOpen,
|
||||
title: 'FAQs',
|
||||
href: dashboard.faq.show(),
|
||||
icon: TableOfContents,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -69,7 +70,6 @@ export function AppSidebar() {
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarFooter>
|
||||
<NavFooter items={footerNavItems} className="mt-auto" />
|
||||
<NavUser />
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { about, artOfWeaving, contact, faq, home, product } from '@/routes';
|
||||
import { about, artOfWeaving, contact, faq, home } from '@/routes';
|
||||
import index from '@/routes/index/index';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import ns from '@asset/img/about/ns.gif';
|
||||
import oko from '@asset/img/about/oko.gif';
|
||||
import logo from '@asset/img/logo/soorya.png';
|
||||
import { SiFacebook, SiInstagram } from '@icons-pack/react-simple-icons';
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { MoveRight } from 'lucide-react';
|
||||
|
||||
export default function Footer() {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<footer className="bg-primary">
|
||||
<div className="mx-auto grid max-w-screen-2xl grid-cols-4 gap-8 px-12 py-8 max-md:grid-cols-1 max-md:grid-rows-4 max-md:px-6">
|
||||
<div className="flex flex-col gap-4">
|
||||
<img src={logo} alt="Soorya Carpet Logo" className="w-32" />
|
||||
<div className="flex flex-col gap-4 text-sm text-white">
|
||||
<p>
|
||||
A beautiful home deserves beautiful carpets Since
|
||||
1974, crafting the finest handmade Nepalese carpets
|
||||
</p>
|
||||
<p>{t('footer.desc.title')}</p>
|
||||
<ul>
|
||||
<li>Soorya Carpet Industries</li>
|
||||
<li>Address: Thapathali, Kathmandu</li>
|
||||
<li>Phone: [+977-1] 4780923, 4783003</li>
|
||||
<li>Email: sooryacarpets@gmail.com</li>
|
||||
<li>{t('footer.desc.company')}</li>
|
||||
<li>{t('footer.desc.address')}</li>
|
||||
<li>{t('footer.desc.phone')}</li>
|
||||
<li>{t('footer.desc.email')}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,17 +33,17 @@ export default function Footer() {
|
||||
<ul className="flex flex-col gap-1 text-sm">
|
||||
<li>
|
||||
<Link href={home()} className="text-neutral-300">
|
||||
Home
|
||||
{t('footer.links.home')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={contact()} className="text-neutral-300">
|
||||
Contact US
|
||||
{t('footer.links.contact')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={about()} className="text-neutral-300">
|
||||
About Us
|
||||
{t('footer.links.about-us')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
@@ -49,27 +51,30 @@ export default function Footer() {
|
||||
href={artOfWeaving()}
|
||||
className="text-neutral-300"
|
||||
>
|
||||
Art of Weaving
|
||||
{t('footer.links.art')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={product()} className="text-neutral-300">
|
||||
Products
|
||||
<Link
|
||||
href={index.product()}
|
||||
className="text-neutral-300"
|
||||
>
|
||||
{t('footer.links.products')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={home()} className="text-neutral-300">
|
||||
Bespoke Design
|
||||
{t('footer.links.bespoke')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={home()} className="text-neutral-300">
|
||||
Design Gallery / E-Catalog
|
||||
{t('footer.links.gallery')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={faq()} className="text-neutral-300">
|
||||
FAQ
|
||||
{t('footer.links.faq')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -78,46 +83,57 @@ export default function Footer() {
|
||||
<p className="text-lg font-medium text-white">
|
||||
Certifications & Trust Badges
|
||||
</p>
|
||||
<div className="grid grid-cols-3 gap-1">
|
||||
<img
|
||||
src={ns}
|
||||
alt="NS Standard"
|
||||
className="aspect-square object-cover object-center"
|
||||
/>
|
||||
<img
|
||||
src={oko}
|
||||
alt="oko Standard"
|
||||
className="object-cover object-center"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex flex-col gap-6">
|
||||
<form className="flex flex-col gap-2">
|
||||
<Label className="text-lg font-medium text-white">
|
||||
Newsletter/Updates
|
||||
{t('footer.news.title')}
|
||||
</Label>
|
||||
<div className="flex items-center gap-2 max-sm:flex-col">
|
||||
<Input
|
||||
id="newsletter"
|
||||
placeholder="Email Address"
|
||||
placeholder={t('footer.news.input')}
|
||||
className="bg-white"
|
||||
/>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="bg-transparent text-white max-sm:w-full"
|
||||
>
|
||||
Subscribe <MoveRight />
|
||||
{t('footer.news.button')} <MoveRight />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-base font-medium text-white">
|
||||
Legal
|
||||
{t('footer.news.legal.title')}
|
||||
</p>
|
||||
<ul className="flex flex-col gap-1 text-sm text-neutral-300">
|
||||
<li>
|
||||
<Link href="privacy-policy">
|
||||
Privacy Policy
|
||||
{t('footer.news.legal.privacy')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="terms-and-condition">
|
||||
Terms & Conditions Return
|
||||
{t('footer.news.legal.terms')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={faq()}>
|
||||
Policy (from FAQ)Privacy Policy (from
|
||||
FAQ)
|
||||
{t('footer.news.legal.policy')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
// import { dashboard, login, register } from '@/routes';
|
||||
// import { SharedData } from '@/types';
|
||||
// import { Link, usePage } from '@inertiajs/react';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
@@ -8,18 +16,55 @@ import {
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@/components/ui/sheet';
|
||||
import { about, artOfWeaving, contact, faq, home, product } from '@/routes';
|
||||
import { about, artOfWeaving, bespoke, contact, faq, home } from '@/routes';
|
||||
import index from '@/routes/index/index';
|
||||
import { useLocale, useTranslations } from '@/utils/i18n';
|
||||
import logo from '@asset/img/logo/soorya.png';
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { Link, router } from '@inertiajs/react';
|
||||
import { Mail, MapPin, Menu, Phone } from 'lucide-react';
|
||||
|
||||
export default function Navbar() {
|
||||
// const [lang, setLang] = useState('en');
|
||||
// const { translations } = usePage().props;
|
||||
// const { post } = useForm({
|
||||
// locale: lang,
|
||||
// });
|
||||
|
||||
// console.log('lang', lang);
|
||||
|
||||
// const changeLanguage = (e) => {
|
||||
// console.log(e);
|
||||
// setLang(e);
|
||||
// post(locale.change().url);
|
||||
// };
|
||||
// const { auth } = usePage<SharedData>().props;
|
||||
|
||||
const { t } = useTranslations();
|
||||
const locale = useLocale();
|
||||
|
||||
// const { locale, translations } = usePage().props;
|
||||
|
||||
const changeLanguage = (newLocale: string) => {
|
||||
router.post(
|
||||
'/locale',
|
||||
{ locale: newLocale },
|
||||
{
|
||||
preserveScroll: true,
|
||||
preserveState: true,
|
||||
onSuccess: () => {
|
||||
// The page will automatically update because Inertia
|
||||
// will make a new request and get the updated translations
|
||||
console.log('Language changed to:', newLocale);
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="mx-auto w-full text-sm not-has-[nav]:hidden">
|
||||
<div className="bg-primary py-1.5 text-white/60 max-md:hidden">
|
||||
<div className="mx-auto max-w-screen-2xl px-12 max-md:px-2">
|
||||
<div className="mx-auto flex max-w-screen-2xl items-center justify-between px-12 max-md:px-2">
|
||||
<ul className="flex items-center gap-4">
|
||||
<li>
|
||||
<a
|
||||
@@ -49,6 +94,19 @@ export default function Navbar() {
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Select value={locale} onValueChange={changeLanguage}>
|
||||
<SelectTrigger className="h-0 w-32 border-0 focus-visible:ring-0">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{/* <SelectLabel>Fruits</SelectLabel> */}
|
||||
<SelectItem value="en">English</SelectItem>
|
||||
<SelectItem value="cn">中国人</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-auto w-full max-w-screen-2xl px-12 py-2 text-base not-has-[nav]:hidden max-md:px-4">
|
||||
@@ -62,24 +120,26 @@ export default function Navbar() {
|
||||
</Link>
|
||||
<ul className="flex items-center gap-6 max-md:hidden">
|
||||
<li>
|
||||
<Link href={about()}>About Us</Link>
|
||||
<Link href={about()}>{t('nav.about-us')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={artOfWeaving()}>
|
||||
Art of Weaving
|
||||
{t('nav.art')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={product()}>Our Products</Link>
|
||||
<Link href={index.product()}>
|
||||
{t('nav.products')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={about()}>Bespoke Design</Link>
|
||||
<Link href={bespoke()}>{t('nav.bespoke')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={faq()}>FAQs</Link>
|
||||
<Link href={faq()}>{t('nav.faq')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={contact()}>Contact Us</Link>
|
||||
<Link href={contact()}>{t('nav.contact')}</Link>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -94,28 +154,32 @@ export default function Navbar() {
|
||||
</SheetDescription>
|
||||
<ul className="mt-20 flex flex-col items-center justify-center gap-6">
|
||||
<li>
|
||||
<Link href={about()}>About Us</Link>
|
||||
<Link href={about()}>
|
||||
{t('nav.about-us')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={artOfWeaving()}>
|
||||
Art of Weaving
|
||||
{t('nav.art')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={product()}>
|
||||
Our Products
|
||||
<Link href={index.product()}>
|
||||
{t('nav.products')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={about()}>
|
||||
Bespoke Design
|
||||
<Link href={bespoke()}>
|
||||
{t('nav.bespoke')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={faq()}>FAQs</Link>
|
||||
<Link href={faq()}>{t('nav.faq')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={contact()}>Contact Us</Link>
|
||||
<Link href={contact()}>
|
||||
{t('nav.contact')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</SheetContent>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import index from '@/routes/index/index';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { MoveRightIcon } from 'lucide-react';
|
||||
import 'swiper/css';
|
||||
@@ -10,6 +12,7 @@ export default function SwiperCarousel({
|
||||
}: {
|
||||
item: [{ image_url: string; alt: string }];
|
||||
}) {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -39,20 +42,22 @@ export default function SwiperCarousel({
|
||||
</Swiper>
|
||||
<div className="absolute bottom-7 left-12 z-50 flex w-md flex-col gap-6 rounded-lg bg-[#FFF5F1]/80 px-12 py-6 font-serif">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h1 className="text-4xl font-medium">
|
||||
Feel More Like Home
|
||||
<h1 className="text-3xl font-medium max-sm:text-lg">
|
||||
{t('pages.home.banner.title')}
|
||||
{/* A Beautiful Home
|
||||
Deserves A Beautiful Carpet */}
|
||||
</h1>
|
||||
<p className="text-xl leading-tight">
|
||||
Carpets that are made with care from ground up
|
||||
<p className="text-xl leading-tight max-sm:text-sm">
|
||||
{t('pages.home.banner.subTitle')}
|
||||
</p>
|
||||
</div>
|
||||
<Link href="">
|
||||
<Link href={index.product().url}>
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
size={'lg'}
|
||||
className="cursor-pointer border border-primary bg-transparent text-lg ring-primary"
|
||||
>
|
||||
Discover More <MoveRightIcon />
|
||||
{t('pages.home.banner.button')} <MoveRightIcon />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,300 @@
|
||||
export default function Testimonial() {
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orientation';
|
||||
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
||||
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
|
||||
import 'filepond/dist/filepond.min.css';
|
||||
import { Star } from 'lucide-react';
|
||||
import { FilePond, registerPlugin } from 'react-filepond';
|
||||
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
import 'swiper/css/pagination';
|
||||
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import { useForm } from '@inertiajs/react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Pagination } from 'swiper/modules';
|
||||
|
||||
// const testimonial = [
|
||||
// {
|
||||
// name: 'Priya Sharada',
|
||||
// company: 'Sharada Group',
|
||||
// review: 'What impressed me the most was the attention to detail and the evident care put into making the rug, It has become a center piece in my living room, gathering compliments from everyone who sees it. If you are considering handmade rugs, I highly recommend Kaleen.',
|
||||
// img: testimonial1,
|
||||
// },
|
||||
// {
|
||||
// name: 'Kedar Bhakta Mathema',
|
||||
// company:
|
||||
// 'Former VC of Tribhuwan University, Nepal, Former Nepalese Ambassador to Japan',
|
||||
// review: 'I am delighted to recommend Kaleen Carpet in Kathmandu to anyone seeking skilled carpet weavers. What impressed me most about Kaleen was their willingness to make several changes to the design at my request without any hesitation. I find Kaleen to be highly professional and trustworthy in all their dealings.',
|
||||
// img: testimonial3,
|
||||
// },
|
||||
// {
|
||||
// name: 'Ani Rudra Silwal and Srijana Silwal',
|
||||
// company: 'USA',
|
||||
// review: "Thank you for making these carpets for us! We couldn't be more pleased with them. The entire process - from the custom design to shipping - was seamless and very professional. We look forward to having these beautiful Nepali handmade carpets in our home for many years to come!",
|
||||
// img: testimonial1,
|
||||
// },
|
||||
// {
|
||||
// name: 'Manila Pradhan and Bhaskar Joshi',
|
||||
// company: 'USA',
|
||||
// review: 'We absolutely love the carpet. Thank you so much for the excellent design and execution.',
|
||||
// img: testimonial2,
|
||||
// },
|
||||
// ];
|
||||
export default function Testimonial({
|
||||
testimonial,
|
||||
}: {
|
||||
testimonial: [
|
||||
{
|
||||
name: string;
|
||||
location: string;
|
||||
image: string;
|
||||
description: string;
|
||||
},
|
||||
];
|
||||
}) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [file, setFile] = useState<any | null>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
const { data, setData, post, processing, errors } = useForm({
|
||||
name: '',
|
||||
location: '',
|
||||
description: '',
|
||||
image: null as File | null,
|
||||
});
|
||||
registerPlugin(
|
||||
FilePondPluginImageExifOrientation,
|
||||
FilePondPluginImagePreview,
|
||||
);
|
||||
useEffect(() => {
|
||||
if (file) {
|
||||
setData('image', file.file);
|
||||
}
|
||||
}, [file, setData]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
post('/testimonial', {
|
||||
// forceFormData: true,
|
||||
onSuccess: () => {
|
||||
toast.success('Testimonial successfully uploaded!');
|
||||
setOpen(false);
|
||||
setFile(null);
|
||||
setData({
|
||||
name: '',
|
||||
location: '',
|
||||
description: '',
|
||||
image: null,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<h4>Testimonials</h4>
|
||||
<div></div>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col items-center gap-12 px-16 py-12 max-sm:px-8">
|
||||
<h4 className="text-center font-serif text-4xl font-medium">
|
||||
{t('pages.home.sections.testimonial.title')}
|
||||
</h4>
|
||||
{/* <div className="grid grid-cols-4 gap-8 max-lg:grid-cols-2 max-md:grid-cols-2 max-sm:grid-cols-1">
|
||||
{testimonial.map((review) => (
|
||||
<div className="flex flex-col items-center gap-4 rounded-lg border border-gray-300 px-6 py-6 text-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
<img
|
||||
src={review.image}
|
||||
alt={review.name}
|
||||
className="mb-4 aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
<p className="text-lg font-bold">
|
||||
{review.name}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
{review.location}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm text-gray-800">
|
||||
{review.description}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center">
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div> */}
|
||||
<div
|
||||
className="relative max-w-7xl overflow-clip max-sm:max-w-sm"
|
||||
id="testimonial"
|
||||
>
|
||||
<Swiper
|
||||
spaceBetween={16}
|
||||
slidesPerView={4}
|
||||
breakpoints={{
|
||||
432: {
|
||||
slidesPerView: 2,
|
||||
spaceBetween: 8,
|
||||
},
|
||||
768: {
|
||||
slidesPerView: 3,
|
||||
spaceBetween: 8,
|
||||
},
|
||||
1024: {
|
||||
slidesPerView: 4,
|
||||
spaceBetween: 16,
|
||||
},
|
||||
}}
|
||||
loop={true}
|
||||
autoplay={{
|
||||
delay: 1500,
|
||||
}}
|
||||
className="w-full"
|
||||
pagination={true}
|
||||
// navigation={true}
|
||||
modules={[Pagination]}
|
||||
>
|
||||
{testimonial.map((review) => (
|
||||
<SwiperSlide className="relative overflow-clip">
|
||||
<div className="flex flex-col items-center gap-4 rounded-lg border border-gray-300 px-6 py-6 text-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
<img
|
||||
src={review.image}
|
||||
alt={review.name}
|
||||
className="mb-4 aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
<p className="text-lg font-bold">
|
||||
{review.name}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
{review.location}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm text-gray-800">
|
||||
{review.description}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center">
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
</div>
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
</div>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button className="cursor-pointer">
|
||||
{t('pages.home.sections.testimonial.button')}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="!max-w-3xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Give your testimonial</DialogTitle>
|
||||
<DialogDescription></DialogDescription>
|
||||
<form
|
||||
className="grid gap-4"
|
||||
onSubmit={handleSubmit}
|
||||
method="POST"
|
||||
>
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="name">Name</Label>
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder="Enter your name"
|
||||
value={data.name}
|
||||
onChange={(e) =>
|
||||
setData('name', e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="company">Location</Label>
|
||||
<Input
|
||||
id="company"
|
||||
name="location"
|
||||
placeholder="Enter you location (e.g. Private Company / Country Name)"
|
||||
value={data.location}
|
||||
onChange={(e) =>
|
||||
setData('location', e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="review">Description</Label>
|
||||
<Textarea
|
||||
id="review"
|
||||
name="review"
|
||||
cols={20}
|
||||
placeholder="Write your review..."
|
||||
value={data.description}
|
||||
onChange={(e) =>
|
||||
setData(
|
||||
'description',
|
||||
e.target.value,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3">
|
||||
<Label>Image</Label>
|
||||
<FilePond
|
||||
files={file ? [file] : []}
|
||||
onupdatefiles={(fileItems) => {
|
||||
setFile(fileItems[0] || null);
|
||||
}}
|
||||
allowMultiple={false}
|
||||
maxFiles={1}
|
||||
name="image"
|
||||
instantUpload={false}
|
||||
storeAsFile={true}
|
||||
labelIdle='Drag & Drop your image or <span class="filepond--label-action">Browse</span>'
|
||||
/>
|
||||
{errors.image && (
|
||||
<span className="text-red-600">
|
||||
{errors.image}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={processing}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{processing
|
||||
? 'Submitting...'
|
||||
: 'Submit Now'}
|
||||
</Button>
|
||||
</form>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import ourStory from '@asset/img/about/A1PG1ALsIBL._AC_UF894,1000_QL80_.jpg';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import kaleen from '@asset/img/about/kaleen.jpg';
|
||||
import ns from '@asset/img/about/ns.gif';
|
||||
import oko from '@asset/img/about/oko.gif';
|
||||
import ourStory from '@asset/img/products/sci trad 8.jpg';
|
||||
import { Head } from '@inertiajs/react';
|
||||
|
||||
import { HeartHandshake, Lightbulb, Target } from 'lucide-react';
|
||||
export default function About() {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Head title="About Us">
|
||||
@@ -20,49 +22,19 @@ export default function About() {
|
||||
<div className="grid h-1/2 grid-cols-2 gap-20 overflow-clip max-md:grid-cols-1 max-md:gap-12">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h1 className="font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
|
||||
Our Story: Crafting Legacies Since 1974
|
||||
{t('pages.about.sections.first.title')}
|
||||
</h1>
|
||||
<div className="flex flex-col gap-4 text-sm max-sm:text-base">
|
||||
<p>
|
||||
The story of Soorya Carpet Industries begins
|
||||
in the early 1970s, when Mr. Laxman Shrestha
|
||||
and Mrs. Renuka Shrestha left their village
|
||||
in Dolakha and moved to Kathmandu with the
|
||||
ambition of building something meaningful.
|
||||
What started as a small rug-weaving
|
||||
initiative in a single room eventually grew
|
||||
into one of Nepal’s largest carpet
|
||||
manufacturing enterprises. Through
|
||||
perseverance and vision, they provided
|
||||
livelihoods to more than 1,000 skilled and
|
||||
unskilled workers and made a significant
|
||||
contribution to the country’s GDP. For over
|
||||
two decades, Soorya Carpet Industries earned
|
||||
international recognition, particularly in
|
||||
Germany, for exporting high-quality,
|
||||
hand-knotted carpets.
|
||||
{t('pages.about.sections.first.desc.first')}
|
||||
</p>
|
||||
<p>
|
||||
By the late 1990s, however, Nepal’s carpet
|
||||
industry suffered severe setbacks owing to
|
||||
economic, social, and political challenges.
|
||||
Global scrutiny following child labour
|
||||
controversies in the wider industry, coupled
|
||||
with the instability caused by the Maoist
|
||||
insurgency, crippled the sector. Like many
|
||||
others, Soorya Carpet Industries was forced
|
||||
to scale down and eventually suspend
|
||||
production.
|
||||
{t(
|
||||
'pages.about.sections.first.desc.second',
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
The industry never quite returned to its
|
||||
early-1990s mass-scale export peak, yet it
|
||||
found ways to reinvent itself and stay
|
||||
relevant. Recognizing this shift, Soorya
|
||||
Carpet Industries transitioned from
|
||||
large-scale production to a boutique model,
|
||||
focusing on the niche luxury segment with
|
||||
custom-made, limited-edition rugs.
|
||||
{t('pages.about.sections.first.desc.third')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,35 +52,23 @@ export default function About() {
|
||||
/>
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
|
||||
The Kaleen Rebrand Story: A New Chapter
|
||||
{t('pages.about.sections.second.title')}
|
||||
</h2>
|
||||
<div className="flex flex-col gap-4 text-sm max-sm:text-base">
|
||||
<p>
|
||||
Guided by the aspiration to create premium,
|
||||
ethical and artistic carpets, this journey
|
||||
led to the launch of Kaleen—our exclusive
|
||||
designer carpet brand.
|
||||
{t(
|
||||
'pages.about.sections.second.desc.first',
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
Kaleen celebrates craftsmanship, artistry,
|
||||
and ethics. We create bespoke,
|
||||
limited-edition rugs that range from
|
||||
time-honoured traditional designs to bold,
|
||||
innovative forms, all crafted to complement
|
||||
modern interiors and aesthetics. Our
|
||||
collections are inspired by beautiful
|
||||
landscapes of Nepal and the five elements of
|
||||
life: Fire, Water, Earth, Air, and Metal.
|
||||
{t(
|
||||
'pages.about.sections.second.desc.second',
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
Handmade carpets have long been central to
|
||||
interior design—a tradition that remains
|
||||
timeless. At Kaleen, we are proud to carry
|
||||
this heritage forward with integrity and
|
||||
creativity. Our ambition is to build a
|
||||
strong brand identity, uphold ethical
|
||||
credibility, and expand into discerning
|
||||
global markets.
|
||||
{t(
|
||||
'pages.about.sections.second.desc.third',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -117,47 +77,53 @@ export default function About() {
|
||||
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-12 max-md:px-6">
|
||||
<h3 className="text-center font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
|
||||
Our Guiding Principles
|
||||
{t('pages.about.sections.third.title')}
|
||||
</h3>
|
||||
<div className="flex gap-8 max-md:flex-col">
|
||||
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center max-sm:px-4">
|
||||
<Lightbulb size={48} color="#5A1A1A" />
|
||||
<p className="font-serif text-3xl font-semibold">
|
||||
Our vision
|
||||
{t(
|
||||
'pages.about.sections.third.cards.first.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-center">
|
||||
To be the global leader in luxury handcrafted
|
||||
carpets, renowned for unparalleled quality,
|
||||
innovative design, and sustainable practices.
|
||||
<p className="text-justify text-lg tracking-tight">
|
||||
{t(
|
||||
'pages.about.sections.third.cards.first.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>{' '}
|
||||
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center">
|
||||
<Target size={48} color="#5A1A1A" />
|
||||
<p className="font-serif text-3xl font-semibold">
|
||||
Our Mission
|
||||
{t(
|
||||
'pages.about.sections.third.cards.second.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-center">
|
||||
To meticulously craft exquisite carpets that
|
||||
enrich lives and spaces, preserving artisanal
|
||||
heritage while inspiring contemporary design.
|
||||
<p className="text-justify text-lg tracking-tight">
|
||||
{t(
|
||||
'pages.about.sections.third.cards.second.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>{' '}
|
||||
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center">
|
||||
<HeartHandshake size={48} color="#5A1A1A" />
|
||||
<p className="font-serif text-3xl font-semibold">
|
||||
Our Promise
|
||||
{t(
|
||||
'pages.about.sections.third.cards.third.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-center">
|
||||
We promise exceptional artistry, ethical
|
||||
sourcing, and personalized service, ensuring
|
||||
every Kaleen carpet is a timeless masterpiece.
|
||||
<p className="text-justify text-lg tracking-tight">
|
||||
{t(
|
||||
'pages.about.sections.third.cards.third.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-12">
|
||||
<h4 className="text-center font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
|
||||
Our Commitment to Quality & Ethics
|
||||
{t('pages.about.sections.fourth.title')}
|
||||
</h4>
|
||||
<div className="flex items-center justify-center gap-8">
|
||||
<img src={ns} alt="NS Standard" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import artOfWeaving from '@asset/img/art/IMG_4715.jpg';
|
||||
import skill from '@asset/img/material/silk balls.jpg';
|
||||
import skillYarn from '@asset/img/material/silk yarn.jpg';
|
||||
import woolBall from '@asset/img/material/wool balls.jpg';
|
||||
import woolYarn from '@asset/img/material/wool yarn.jpg';
|
||||
import artOfWeaving from '@asset/img/production/IMG_2719.jpg';
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { Flower, Hand, Package, Palette, Shirt } from 'lucide-react';
|
||||
|
||||
@@ -15,11 +15,11 @@ export default function Art() {
|
||||
<Head title="Art of Weaving" />
|
||||
<section>
|
||||
<div className="relative">
|
||||
<div className="absolute h-full w-full bg-white/70"></div>
|
||||
<div className="absolute h-full w-full bg-white/60"></div>
|
||||
<img
|
||||
src={artOfWeaving}
|
||||
alt="Art of Weaving"
|
||||
className="aspect-[16/4] object-cover object-top"
|
||||
className="aspect-[16/4] object-cover object-center"
|
||||
/>
|
||||
<h1 className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 font-serif text-7xl font-medium tracking-tight">
|
||||
The Art of Weaving
|
||||
|
||||
128
resources/js/pages/bespoke.tsx
Normal file
128
resources/js/pages/bespoke.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import bespokeHeader from '@asset/img/products/color swatches.jpg';
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { ClipboardList, Paintbrush, Palette, Truck } from 'lucide-react';
|
||||
|
||||
export default function Bespoke({
|
||||
product,
|
||||
}: {
|
||||
product: [{ id: number; title: string; type: string; image_url: string }];
|
||||
}) {
|
||||
console.log(product);
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<Head title="Bespoke Design" />
|
||||
<section className="">
|
||||
<div className="relative">
|
||||
<div className="absolute h-full w-full bg-white/30"></div>
|
||||
<img
|
||||
src={bespokeHeader}
|
||||
alt="Bespoke Design"
|
||||
className="aspect-[16/4] object-cover object-center max-sm:aspect-[16/9]"
|
||||
/>
|
||||
<div className="absolute top-1/2 left-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col gap-2">
|
||||
<h1 className="text-center font-serif text-5xl font-medium tracking-tight max-md:text-4xl max-sm:text-2xl">
|
||||
{t('pages.bespoke.sections.banner.title')}
|
||||
</h1>
|
||||
<p className="text-center text-lg text-gray-800 max-sm:text-sm">
|
||||
{t('pages.bespoke.sections.banner.subTitle')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-18 max-sm:px-8">
|
||||
<h2 className="text-center font-serif text-4xl font-medium max-md:text-2xl">
|
||||
{t('pages.bespoke.sections.first.title')}
|
||||
</h2>
|
||||
<div className="grid grid-cols-4 gap-4 max-md:grid-cols-2 max-sm:grid-cols-1">
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<ClipboardList size={40} color="#5A1A1A" />
|
||||
<p className="text-center font-serif text-xl font-medium">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.first.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="px-4 text-center text-sm">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.first.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Palette size={40} color="#5A1A1A" />
|
||||
<p className="text-center font-serif text-xl font-medium">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.second.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="px-4 text-center text-sm">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.second.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Paintbrush size={40} color="#5A1A1A" />
|
||||
<p className="text-center font-serif text-xl font-medium">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.third.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="px-4 text-center text-sm">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.third.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Truck size={40} color="#5A1A1A" />
|
||||
<p className="text-center font-serif text-xl font-medium">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.fourth.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="px-4 text-center text-sm">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.fourth.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-18 max-sm:px-8">
|
||||
<h3 className="text-center font-serif text-4xl font-medium max-md:text-2xl">
|
||||
Bespoke Product
|
||||
</h3>
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
{product.map((item) => (
|
||||
<img
|
||||
src={item.image_url}
|
||||
alt={item.title}
|
||||
className="aspect-[4/5] rounded-lg object-cover object-center"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col items-center gap-8 px-12 py-18 max-sm:px-8">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<h4 className="text-center font-serif text-4xl font-medium max-md:text-2xl">
|
||||
{t('pages.bespoke.sections.second.title')}
|
||||
</h4>
|
||||
<p className="text-center max-md:text-sm">
|
||||
{t('pages.bespoke.sections.second.desc')} <br />{' '}
|
||||
{t('pages.bespoke.sections.second.desc2')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Button className="cursor-pointer">
|
||||
{t('pages.bespoke.sections.second.button')}
|
||||
</Button>
|
||||
</section>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -10,10 +10,12 @@ import {
|
||||
} from '@/components/ui/select';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import { Form, Head } from '@inertiajs/react';
|
||||
import { Mail, MapPin, Phone } from 'lucide-react';
|
||||
|
||||
export default function Contact() {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
@@ -21,64 +23,79 @@ export default function Contact() {
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-12 max-md:px-8">
|
||||
<div className="flex flex-col gap-4">
|
||||
<h1 className="text-center font-serif text-5xl font-medium tracking-tight max-md:text-3xl">
|
||||
Connect with Kaleen Carpets
|
||||
{t('pages.contact.sections.first.title')}
|
||||
</h1>
|
||||
<p className="text-center text-sm">
|
||||
We are here to assist you with any inquiries,
|
||||
bespoke design requests, or partnership
|
||||
opportunities. <br /> Reach out to our team through
|
||||
our offices or the contact form below.
|
||||
{t('pages.contact.sections.first.subTitle')} <br />{' '}
|
||||
{t('pages.contact.sections.first.subTitle2')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-8">
|
||||
<h2 className="text-center font-serif text-3xl font-medium tracking-tight">
|
||||
Our Global Offices
|
||||
{t('pages.contact.sections.second.title')}
|
||||
</h2>
|
||||
<div className="flex items-start justify-center gap-24 max-md:flex-col max-md:gap-12">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="font-serif text-xl font-medium tracking-tight">
|
||||
Soorya Carpet Industries
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
Our global presence to serve you better.
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.subTitle',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul className="flex flex-col gap-2">
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<MapPin size={16} /> G.P.O Box 1765 2
|
||||
Swet Binayak Marg Thapathali -11,
|
||||
Kathmandu, Nepal
|
||||
<MapPin size={16} />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.address',
|
||||
)}
|
||||
</li>{' '}
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<Phone size={16} /> [+977-1] 4780923,
|
||||
4783003
|
||||
<Phone size={16} />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.phone',
|
||||
)}
|
||||
</li>{' '}
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<Mail size={16} />{' '}
|
||||
sooryacarpets@gmail.com
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.email',
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="font-serif text-xl font-medium tracking-tight">
|
||||
Kaleen Studio
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
Our global presence to serve you better.
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.subTitle',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul className="flex flex-col gap-2">
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<MapPin size={16} /> Kadel Chautari
|
||||
Prasuti Griha Marg Ward No. 11,
|
||||
Babarmahal Kathmandu, Nepal
|
||||
<MapPin size={16} />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.address',
|
||||
)}
|
||||
</li>{' '}
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<Phone size={16} /> 9802341880
|
||||
<Phone size={16} />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.phone',
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
<a
|
||||
@@ -90,7 +107,9 @@ export default function Contact() {
|
||||
className="w-full cursor-pointer border border-primary text-primary ring-primary"
|
||||
variant={'outline'}
|
||||
>
|
||||
Visit Studio
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.button',
|
||||
)}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
@@ -100,36 +119,55 @@ export default function Contact() {
|
||||
<div className="mx-auto flex w-full max-w-3xl flex-col gap-8 py-12">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="font-serif text-3xl font-medium">
|
||||
Send us a Message
|
||||
{t('pages.contact.sections.third.title')}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500">
|
||||
Fill out the form below and we'll get back to
|
||||
you as soon as possible.
|
||||
{t('pages.contact.sections.third.subTitle')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Form action={'/'} className="flex flex-col gap-2">
|
||||
<div>
|
||||
<Label htmlFor="name">Name</Label>
|
||||
<Label htmlFor="name">
|
||||
{t(
|
||||
'pages.contact.sections.third.form.name.label',
|
||||
)}
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="Full Name"
|
||||
placeholder={t(
|
||||
'pages.contact.sections.third.form.name.input',
|
||||
)}
|
||||
id="name"
|
||||
name="name"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Label htmlFor="email">
|
||||
{t(
|
||||
'pages.contact.sections.third.form.email.label',
|
||||
)}
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="your.email@example.com"
|
||||
placeholder={t(
|
||||
'pages.contact.sections.third.form.email.input',
|
||||
)}
|
||||
id="email"
|
||||
name="email"
|
||||
/>
|
||||
</div>{' '}
|
||||
<div>
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Label htmlFor="email">
|
||||
{t(
|
||||
'pages.contact.sections.third.form.inquiry.label',
|
||||
)}
|
||||
</Label>
|
||||
<Select>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select an inquiry type" />
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
'pages.contact.sections.third.form.inquiry.input',
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="problem">
|
||||
@@ -142,31 +180,38 @@ export default function Contact() {
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="message">Message</Label>
|
||||
<Label htmlFor="message">
|
||||
{t(
|
||||
'pages.contact.sections.third.form.message.label',
|
||||
)}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="message"
|
||||
placeholder="Tell us how can we help you"
|
||||
placeholder={t(
|
||||
'pages.contact.sections.third.form.message.input',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" className="my-4">
|
||||
Send Message
|
||||
{t('pages.contact.sections.third.form.button')}
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-8">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<h4 className="text-center font-serif text-3xl font-medium tracking-tight">
|
||||
Direct Engagement
|
||||
{t('pages.contact.sections.fourth.title')}
|
||||
</h4>
|
||||
<p className="text-center text-sm text-gray-500">
|
||||
Prefer to speak with us directly or send a quick
|
||||
email? <br /> Our team is ready to assist.
|
||||
{t('pages.contact.sections.fourth.desc')} <br />{' '}
|
||||
{t('pages.contact.sections.fourth.desc2')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<a href="tel:9802341880">
|
||||
<Button className="cursor-pointer">
|
||||
<Phone /> Call Us Now
|
||||
<Phone />{' '}
|
||||
{t('pages.contact.sections.fourth.callBtn')}
|
||||
</Button>
|
||||
</a>
|
||||
<a href="mailto:info@soory.com">
|
||||
@@ -174,7 +219,10 @@ export default function Contact() {
|
||||
variant={'outline'}
|
||||
className="cursor-pointer border border-primary text-primary ring-primary"
|
||||
>
|
||||
<Mail /> Email Our Team
|
||||
<Mail />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.fourth.emailBtn',
|
||||
)}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -7,13 +7,14 @@ import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orien
|
||||
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
||||
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
|
||||
import 'filepond/dist/filepond.min.css';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FilePond, registerPlugin } from 'react-filepond';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
|
||||
|
||||
export default function CarouselAdd() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [file, setFile] = useState<any | null>(null);
|
||||
|
||||
const { data, setData, post, processing, errors, wasSuccessful } = useForm({
|
||||
@@ -21,12 +22,14 @@ export default function CarouselAdd() {
|
||||
image_url: null as File | null,
|
||||
});
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
useEffect(() => {
|
||||
if (file) {
|
||||
setData('image_url', file.file);
|
||||
}
|
||||
}, [file, setData]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
post('/carousel', {
|
||||
forceFormData: true,
|
||||
@@ -72,7 +75,7 @@ export default function CarouselAdd() {
|
||||
}}
|
||||
allowMultiple={false}
|
||||
maxFiles={1}
|
||||
name="image_url" // Change this to match your backend expectation
|
||||
name="image_url"
|
||||
instantUpload={false}
|
||||
storeAsFile={true}
|
||||
labelIdle='Drag & Drop your image or <span class="filepond--label-action">Browse</span>'
|
||||
@@ -84,7 +87,11 @@ export default function CarouselAdd() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button type="submit" disabled={processing}>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={processing}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{processing ? 'Uploading...' : 'Submit'}
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
@@ -31,7 +31,9 @@ export default function Carousel({
|
||||
Carousel
|
||||
</h1>
|
||||
<Link href={dashboardcarousel.add()}>
|
||||
<Button>Add Image</Button>
|
||||
<Button className="cursor-pointer">
|
||||
Add Image
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<Table>
|
||||
|
||||
162
resources/js/pages/dashboard/products/add.tsx
Normal file
162
resources/js/pages/dashboard/products/add.tsx
Normal file
@@ -0,0 +1,162 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import AppLayout from '@/layouts/app-layout';
|
||||
import dashboard from '@/routes/dashboard';
|
||||
import { Head, useForm } from '@inertiajs/react';
|
||||
import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orientation';
|
||||
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
||||
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
|
||||
import 'filepond/dist/filepond.min.css';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FilePond, registerPlugin } from 'react-filepond';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
|
||||
|
||||
export default function CarouselAdd() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [file, setFile] = useState<any | null>(null);
|
||||
// const [type, setType] = useState<string>('traditional');
|
||||
|
||||
const { data, setData, post, processing, errors, wasSuccessful } = useForm({
|
||||
title: '',
|
||||
type: 'traditional',
|
||||
image_url: null as File | null,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (file) {
|
||||
setData('image_url', file.file);
|
||||
}
|
||||
}, [file, setData]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
post(dashboard.product.add().url, {
|
||||
forceFormData: true,
|
||||
});
|
||||
|
||||
if (wasSuccessful) {
|
||||
toast.success('Product added successfully');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
<Head title="Add Product Image" />
|
||||
<section className="flex flex-col gap-8 px-8 py-8">
|
||||
<h1 className="text-lg font-semibold tracking-tight">
|
||||
Add Product Image
|
||||
</h1>
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
method="POST"
|
||||
encType="multipart/formdata"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Label htmlFor="title">Title</Label>
|
||||
<Input
|
||||
type="text"
|
||||
id="title"
|
||||
value={data.title}
|
||||
onChange={(e) =>
|
||||
setData('title', e.target.value)
|
||||
}
|
||||
className="rounded border p-2"
|
||||
/>
|
||||
{errors.title && (
|
||||
<span className="text-red-600">
|
||||
{errors.title}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Label htmlFor="title">Type</Label>
|
||||
<Select
|
||||
value={data.type}
|
||||
onValueChange={(e) => {
|
||||
console.log(e);
|
||||
setData('type', e);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="traditional">
|
||||
Traditional
|
||||
</SelectItem>
|
||||
<SelectItem value="modern">
|
||||
Modern
|
||||
</SelectItem>
|
||||
<SelectItem value="bespoke">
|
||||
Bespoke
|
||||
</SelectItem>
|
||||
<SelectItem value="abstract">
|
||||
Abstract
|
||||
</SelectItem>
|
||||
<SelectItem value="art">
|
||||
Art in carpet
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{/* <Input
|
||||
type="text"
|
||||
id="title"
|
||||
value={data.alt}
|
||||
onChange={(e) => setData('alt', e.target.value)}
|
||||
className="rounded border p-2"
|
||||
/>
|
||||
{errors.alt && (
|
||||
<span className="text-red-600">{errors.alt}</span>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<Label>Image</Label>
|
||||
<FilePond
|
||||
files={file ? [file] : []}
|
||||
onupdatefiles={(fileItems) => {
|
||||
setFile(fileItems[0] || null);
|
||||
}}
|
||||
allowMultiple={false}
|
||||
maxFiles={1}
|
||||
name="image_url"
|
||||
instantUpload={false}
|
||||
storeAsFile={true}
|
||||
labelIdle='Drag & Drop your image or <span class="filepond--label-action">Browse</span>'
|
||||
/>
|
||||
{errors.image_url && (
|
||||
<span className="text-red-600">
|
||||
{errors.image_url}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={processing}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{processing ? 'Uploading...' : 'Submit'}
|
||||
</Button>
|
||||
</form>
|
||||
</section>
|
||||
</AppLayout>
|
||||
);
|
||||
}
|
||||
0
resources/js/pages/dashboard/products/edit.tsx
Normal file
0
resources/js/pages/dashboard/products/edit.tsx
Normal file
82
resources/js/pages/dashboard/products/index.tsx
Normal file
82
resources/js/pages/dashboard/products/index.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import AppLayout from '@/layouts/app-layout';
|
||||
import dashboard from '@/routes/dashboard';
|
||||
import { Head, Link } from '@inertiajs/react';
|
||||
import { Pencil, Trash2 } from 'lucide-react';
|
||||
|
||||
export default function Product({
|
||||
product,
|
||||
}: {
|
||||
product: [{ title: string; type: string; image_url: string }];
|
||||
}) {
|
||||
return (
|
||||
<AppLayout
|
||||
breadcrumbs={[
|
||||
{ title: 'Products', href: dashboard.product.index().url },
|
||||
]}
|
||||
>
|
||||
<Head title="Products" />
|
||||
|
||||
<section className="flex flex-col gap-8 px-8 py-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-semibold tracking-tight">
|
||||
Products
|
||||
</h1>
|
||||
<Link href={dashboard.product.add()}>
|
||||
<Button className="cursor-pointer">Add Image</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[80px]">S.N.</TableHead>
|
||||
<TableHead className="w-48">Image</TableHead>
|
||||
<TableHead>Title</TableHead>
|
||||
<TableHead className="w-24">Type</TableHead>
|
||||
<TableHead className="text-right">Action</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{product.map((item, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell className="font-medium">
|
||||
{index + 1}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<img
|
||||
src={item.image_url}
|
||||
alt={item.title}
|
||||
className="aspect-video w-24 rounded-md object-cover object-center"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{item.title}</TableCell>
|
||||
<TableCell>{item.type}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<Link href="">
|
||||
<Pencil size={18} />
|
||||
</Link>
|
||||
<Link href="">
|
||||
<Trash2
|
||||
size={18}
|
||||
color={'#D2042D'}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</section>
|
||||
</AppLayout>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,82 @@
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import AppLayout from '@/layouts/app-layout';
|
||||
import testimonial from '@/routes/testimonial';
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { index } from '@/routes/testimonial';
|
||||
import { Head, Link } from '@inertiajs/react';
|
||||
import { Pencil, Trash2 } from 'lucide-react';
|
||||
|
||||
export default function Testimonial() {
|
||||
export default function Testimonial({
|
||||
testimonial,
|
||||
}: {
|
||||
testimonial: [
|
||||
{ name: string; description: string; location: string; image: string },
|
||||
];
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<AppLayout
|
||||
breadcrumbs={[
|
||||
{ title: 'testimonial', href: testimonial.index().url },
|
||||
]}
|
||||
breadcrumbs={[{ title: 'Testimonial', href: index().url }]}
|
||||
>
|
||||
<Head title={'Testimonials'}></Head>
|
||||
<section className="flex flex-col gap-8 px-8 py-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-semibold tracking-tight">
|
||||
Testimonial
|
||||
</h1>
|
||||
</div>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[80px]">S.N.</TableHead>
|
||||
<TableHead className="w-48">Image</TableHead>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Location</TableHead>
|
||||
<TableHead>Description</TableHead>
|
||||
<TableHead className="text-right">
|
||||
Action
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{testimonial.map((item, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell className="font-medium">
|
||||
{index + 1}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<img
|
||||
src={item.image}
|
||||
alt={item.name}
|
||||
className="aspect-video w-24 rounded-md object-cover object-center"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{item.name}</TableCell>
|
||||
<TableCell>{item.location}</TableCell>
|
||||
<TableCell>{item.description}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<Link href="">
|
||||
<Pencil size={18} />
|
||||
</Link>
|
||||
<Link href="">
|
||||
<Trash2
|
||||
size={18}
|
||||
color={'#D2042D'}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</section>
|
||||
</AppLayout>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -7,6 +7,10 @@ import {
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { contact } from '@/routes';
|
||||
import img1 from '@asset/img/Bespoke/bes 5.jpg';
|
||||
import img4 from '@asset/img/Bespoke/Ree 6.jpg';
|
||||
import img3 from '@asset/img/Bespoke/Shrek.jpg';
|
||||
import img2 from '@asset/img/Bespoke/Swarovsky embedded wall hang.jpg';
|
||||
import { Head, Link } from '@inertiajs/react';
|
||||
|
||||
export default function Faq() {
|
||||
@@ -14,8 +18,8 @@ export default function Faq() {
|
||||
<>
|
||||
<Layout>
|
||||
<Head title="FAQs" />
|
||||
<section className="mx-auto flex max-w-screen-2xl gap-32 px-12 py-8">
|
||||
<div className="flex flex-col gap-4">
|
||||
<section className="mx-auto grid max-w-screen-2xl grid-cols-12 gap-32 px-12 py-8 max-sm:grid-cols-1 max-sm:gap-8 max-sm:px-8">
|
||||
<div className="col-span-4 flex flex-col items-start gap-4">
|
||||
<div>
|
||||
<h1 className="font-serif text-4xl font-medium tracking-tight">
|
||||
Frequently Asked Questions
|
||||
@@ -30,50 +34,51 @@ export default function Faq() {
|
||||
Contact Now
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<div className="mt-8 grid grid-cols-2 gap-2 max-sm:mt-2 max-sm:hidden">
|
||||
<div className="flex flex-col gap-2">
|
||||
<img
|
||||
src={img1}
|
||||
alt="Image 1"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
<img
|
||||
src={img4}
|
||||
alt="Image 4"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-8 flex flex-col gap-2">
|
||||
<img
|
||||
src={img2}
|
||||
alt="Image 2"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
<img
|
||||
src={img3}
|
||||
alt="Image 3"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="col-span-8 w-full">
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="w-full"
|
||||
defaultValue="item-1"
|
||||
>
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger className="w-full">
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design
|
||||
pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>{' '}
|
||||
<AccordionItem value="item-2">
|
||||
<AccordionTrigger className="w-full">
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design
|
||||
pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>{' '}
|
||||
<AccordionItem value="item-3">
|
||||
<AccordionTrigger className="w-full">
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design
|
||||
pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>{' '}
|
||||
<AccordionItem value="item-4">
|
||||
<AccordionTrigger className="w-full">
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design
|
||||
pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
{faq.map((item) => (
|
||||
<AccordionItem value={`${item.id}`}>
|
||||
<AccordionTrigger className="w-full">
|
||||
{item?.question}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="px-2 text-gray-600">
|
||||
{item?.answer}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,29 +1,113 @@
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import { Head } from '@inertiajs/react';
|
||||
|
||||
export default function Product() {
|
||||
export default function Product({
|
||||
product,
|
||||
}: {
|
||||
product: [{ title: string; type: string; image_url: string }];
|
||||
}) {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<Head title="Our Products" />
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-8">
|
||||
<h1 className="font-serif text-5xl font-medium tracking-tight">
|
||||
Our Exquisite Collections
|
||||
{t('pages.product.sections.first.title')}
|
||||
</h1>
|
||||
<Tabs defaultValue="account" className="w-[400px]">
|
||||
<TabsList>
|
||||
<TabsTrigger value="account">Account</TabsTrigger>
|
||||
<TabsTrigger value="password">Password</TabsTrigger>
|
||||
<Tabs
|
||||
defaultValue="traditional"
|
||||
className="flex flex-col gap-8"
|
||||
>
|
||||
<TabsList className="flex items-center gap-4 bg-transparent">
|
||||
<TabsTrigger
|
||||
value="traditional"
|
||||
className="!h-auto cursor-pointer px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-white"
|
||||
>
|
||||
{t('pages.product.sections.first.tab1')}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="modern"
|
||||
className="!h-auto cursor-pointer px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-white"
|
||||
>
|
||||
{t('pages.product.sections.first.tab2')}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="abstract"
|
||||
className="!h-auto cursor-pointer px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-white"
|
||||
>
|
||||
{t('pages.product.sections.first.tab3')}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="account">
|
||||
Make changes to your account here.
|
||||
<TabsContent value="traditional">
|
||||
<div className="grid grid-cols-4 gap-6 max-md:grid-cols-3 max-sm:grid-cols-2 max-sm:gap-4">
|
||||
{product.map((e, index) =>
|
||||
e.type === 'traditional' ? (
|
||||
<img
|
||||
key={index}
|
||||
src={e.image_url}
|
||||
alt={e.title}
|
||||
className="aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="password">
|
||||
Change your password here.
|
||||
<TabsContent value="modern">
|
||||
<div className="grid grid-cols-4 gap-6 max-md:grid-cols-3 max-sm:grid-cols-2 max-sm:gap-4">
|
||||
{product.map((e, index) =>
|
||||
e.type === 'modern' ? (
|
||||
<img
|
||||
key={index}
|
||||
src={e.image_url}
|
||||
alt={e.title}
|
||||
className="aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="abstract">
|
||||
<div className="grid grid-cols-4 gap-6 max-md:grid-cols-3 max-sm:grid-cols-2 max-sm:gap-4">
|
||||
{product.map((e, index) =>
|
||||
e.type === 'abstract' ? (
|
||||
<img
|
||||
key={index}
|
||||
src={e.image_url}
|
||||
alt={e.title}
|
||||
className="aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</section>
|
||||
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-8 max-md:px-8">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="font-serif text-3xl font-medium tracking-tight">
|
||||
{t('pages.product.sections.second.title')}
|
||||
</h2>
|
||||
<p className="text-gray-500">
|
||||
{t('pages.product.sections.second.desc')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-6 max-md:grid-cols-3 max-sm:grid-cols-2 max-sm:gap-4">
|
||||
{product.map((e, index) =>
|
||||
e.type === 'art' ? (
|
||||
<img
|
||||
key={index}
|
||||
src={e.image_url}
|
||||
alt={e.title}
|
||||
className="aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Swiper, Testimonial } from '@/components/pages/Home';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { about } from '@/routes';
|
||||
import { about, artOfWeaving } from '@/routes';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import artofWeaving from '@asset/img/carpet/IMG_1301.jpg';
|
||||
import kaleenCarpet from '@asset/img/carpet/IMG_3401.jpg';
|
||||
import sooryaCarpet from '@asset/img/carpet/sci trad 31.jpg';
|
||||
@@ -11,8 +12,19 @@ import { MoveRight } from 'lucide-react';
|
||||
export default function Welcome({
|
||||
data,
|
||||
}: {
|
||||
data: { carousel: [{ image_url: string; alt: string }] };
|
||||
data: {
|
||||
carousel: [{ image_url: string; alt: string }];
|
||||
testimonial: [
|
||||
{
|
||||
name: string;
|
||||
location: string;
|
||||
image: string;
|
||||
description: string;
|
||||
},
|
||||
];
|
||||
};
|
||||
}) {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Head title="Premium Hand Knotted Carpets in Nepal">
|
||||
@@ -38,13 +50,10 @@ export default function Welcome({
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h2 className="font-serif text-3xl font-medium">
|
||||
Soorya Carpet
|
||||
{t('pages.home.sections.first.title')}
|
||||
</h2>
|
||||
<p className="text-gray-500">
|
||||
Discover the journey of Kaleen Carpets, a
|
||||
testament to enduring craftsmanship,
|
||||
innovative design, and a commitment to
|
||||
enriching lives through beautiful artistry.
|
||||
{t('pages.home.sections.first.desc')}
|
||||
</p>
|
||||
</div>
|
||||
<Link href={about()}>
|
||||
@@ -52,7 +61,8 @@ export default function Welcome({
|
||||
variant={'outline'}
|
||||
className="w-fit cursor-pointer border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
Learn More <MoveRight />
|
||||
{t('pages.home.sections.first.button')}{' '}
|
||||
<MoveRight />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -61,21 +71,21 @@ export default function Welcome({
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="font-serif text-3xl font-medium">
|
||||
The Kaleen Rebrand
|
||||
{t('pages.home.sections.second.title')}
|
||||
</h3>
|
||||
<p className="text-gray-500">
|
||||
In 2015, Kaleen embarked on a transformative
|
||||
journey, evolving from a traditional
|
||||
manufacturer to a dynamic, luxury lifestyle
|
||||
brand.
|
||||
{t('pages.home.sections.second.desc')}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="w-fit border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
Learn More <MoveRight />
|
||||
</Button>
|
||||
<Link href={about()}>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="w-fit cursor-pointer border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
{t('pages.home.sections.second.button')}
|
||||
<MoveRight />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<img
|
||||
src={kaleenCarpet}
|
||||
@@ -92,24 +102,24 @@ export default function Welcome({
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h2 className="font-serif text-3xl font-medium">
|
||||
Art of Weaving
|
||||
{t('pages.home.sections.third.title')}
|
||||
</h2>
|
||||
<p className="text-gray-500">
|
||||
Since time immemorial, the art of carpet
|
||||
making has captured millions of carpet
|
||||
connoisseurs from around the world and still
|
||||
continues to do so.
|
||||
{t('pages.home.sections.third.desc')}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="w-fit border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
Learn More <MoveRight />
|
||||
</Button>
|
||||
<Link href={artOfWeaving()}>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="w-fit cursor-pointer border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
{t('pages.home.sections.third.button')}{' '}
|
||||
<MoveRight />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
<Testimonial />
|
||||
<Testimonial testimonial={data?.testimonial} />
|
||||
</div>
|
||||
</Layout>
|
||||
</>
|
||||
|
||||
90
resources/js/utils/i18n.ts
Normal file
90
resources/js/utils/i18n.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { usePage } from '@inertiajs/react';
|
||||
|
||||
// Type definitions for our translations
|
||||
interface Translations {
|
||||
nav: {
|
||||
'about-us': string;
|
||||
art: string;
|
||||
products: string;
|
||||
bespoke: string;
|
||||
faq: string;
|
||||
contact: string;
|
||||
};
|
||||
footer: {
|
||||
desc: {
|
||||
title: string;
|
||||
company: string;
|
||||
address: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
};
|
||||
// Add other translation sections as needed
|
||||
};
|
||||
}
|
||||
|
||||
interface PageProps {
|
||||
locale: string;
|
||||
translations: Translations;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation function
|
||||
*/
|
||||
export function t(
|
||||
translations: any,
|
||||
key: string,
|
||||
replacements: Record<string, string> = {},
|
||||
): string {
|
||||
if (!translations) {
|
||||
console.warn('No translations provided');
|
||||
return key;
|
||||
}
|
||||
|
||||
const keys = key.split('.');
|
||||
let value: any = translations;
|
||||
|
||||
for (const k of keys) {
|
||||
if (value && typeof value === 'object' && k in value) {
|
||||
value = value[k];
|
||||
} else {
|
||||
console.warn(`Translation key not found: ${key}`);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
return key;
|
||||
}
|
||||
|
||||
let text = value;
|
||||
Object.entries(replacements).forEach(([k, v]) => {
|
||||
text = text.replace(new RegExp(`:${k}`, 'g'), v);
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* React hook for translations
|
||||
*/
|
||||
export function useTranslations() {
|
||||
const { translations } = usePage<PageProps>().props;
|
||||
|
||||
const translate = (
|
||||
key: string,
|
||||
replacements: Record<string, string> = {},
|
||||
) => {
|
||||
return t(translations, key, replacements);
|
||||
};
|
||||
|
||||
return { t: translate, translations };
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to get current locale
|
||||
*/
|
||||
export function useLocale() {
|
||||
const { locale } = usePage<PageProps>().props;
|
||||
return locale;
|
||||
}
|
||||
225
resources/lang/cn/message.php
Normal file
225
resources/lang/cn/message.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
return [
|
||||
"nav" => [
|
||||
"about-us" => "关于我们",
|
||||
"art" => "编织的艺术",
|
||||
"products" => "我们的产品",
|
||||
"bespoke" => "定制设计",
|
||||
"faq" => "常见问题",
|
||||
"contact" => "联系我们"
|
||||
],
|
||||
"footer" => [
|
||||
"desc" => [
|
||||
"title" => "美丽的家值得拥有美丽的地毯。自1974年以来,我们一直致力于制作最精美的尼泊尔手工地毯。",
|
||||
"company" => "Soorya 地毯工业",
|
||||
"address" => "地址:加德满都塔帕塔里",
|
||||
"phone" => "电话: [+977-1] 4780923, 4783003",
|
||||
"email" => "邮箱:sooryacarpets@gmail.com",
|
||||
],
|
||||
|
||||
"links" => [
|
||||
"home" => "首页",
|
||||
"contact" => "联系我们",
|
||||
"about-us" => "关于我们",
|
||||
"art" => "编织的艺术",
|
||||
"products" => "我们的产品",
|
||||
"bespoke" => "定制设计",
|
||||
"gallery" => "设计画廊 / 电子目录",
|
||||
"faq" => "常见问题",
|
||||
],
|
||||
"badges" => [
|
||||
"title" => "证书与信任徽章"
|
||||
],
|
||||
"news" => [
|
||||
"title" => "新闻通讯 / 更新",
|
||||
"input" => "电子邮箱地址",
|
||||
"button" => "订阅",
|
||||
"legal" => [
|
||||
"title" => "法律信息",
|
||||
"privacy" => "隐私政策",
|
||||
"terms" => "条款与条件 / 退货政策",
|
||||
"policy" => "政策(来自常见问题)隐私政策(来自常见问题)"
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
"pages" => [
|
||||
"home" => [
|
||||
"banner" => [
|
||||
"title" => "美丽的家值得拥有美丽的地毯",
|
||||
"subTitle" => "从原料到成品,精心制作的地毯",
|
||||
"button" => "了解更多"
|
||||
],
|
||||
"sections" => [
|
||||
"first" => [
|
||||
"title" => "Soorya 地毯",
|
||||
"desc" => "探索 Kaleen 地毯的旅程——这是对持久工艺、创新设计以及通过美丽艺术丰富生活的承诺的见证。",
|
||||
"button" => "了解更多"
|
||||
],
|
||||
"second" => [
|
||||
"title" => "Kaleen 品牌重塑",
|
||||
"desc" => "2015年,Kaleen 开启了一段变革之旅,从传统制造商转型为充满活力的奢侈生活方式品牌。",
|
||||
"button" => "了解更多"
|
||||
],
|
||||
"third" => [
|
||||
"title" => "编织的艺术",
|
||||
"desc" => "自古以来,地毯制作艺术吸引了世界各地无数鉴赏家,并至今仍令人着迷。",
|
||||
"button" => "了解更多"
|
||||
],
|
||||
"testimonial" => [
|
||||
"title" => "客户见证",
|
||||
"button" => "提交您的评价"
|
||||
]
|
||||
]
|
||||
],
|
||||
"about" => [
|
||||
"sections" => [
|
||||
"first" => [
|
||||
"title" => "我们的故事:自1974年以来的传承",
|
||||
"desc" => [
|
||||
"first" =>
|
||||
"Soorya 地毯工业的故事始于20世纪70年代初,拉克斯曼·什雷斯塔先生和雷努卡·什雷斯塔女士离开多拉哈卡的家乡来到加德满都,怀着建立有意义事业的梦想。从一个小房间里的织毯作坊起步,他们最终发展成为尼泊尔最大的地毯制造企业之一。凭借毅力和远见,他们为超过一千名熟练与非熟练工人提供了就业机会,并为国家GDP作出了重大贡献。二十多年来,Soorya 地毯工业因出口高品质的手工打结地毯而在德国等地享有盛誉。",
|
||||
"second" => "
|
||||
然而,到1990年代后期,由于经济、社会和政治挑战,尼泊尔的地毯行业遭受重创。全球对童工问题的审查,加上毛派叛乱造成的不稳定,使整个行业陷入困境。与许多同行一样,Soorya 地毯工业被迫缩减规模并最终暂停生产。",
|
||||
"third" => "
|
||||
尽管行业再未回到90年代初的大规模出口巅峰,但它找到了重新定位的方式。Soorya 地毯工业意识到这一转变,从大规模生产转向精品化模式,专注于定制的奢侈地毯细分市场。"
|
||||
]
|
||||
],
|
||||
"second" => [
|
||||
"title" => "Kaleen 品牌重塑:新篇章",
|
||||
"desc" => [
|
||||
"first" => "秉持打造高端、道德与艺术地毯的理念,我们推出了专属设计师品牌——Kaleen。",
|
||||
"second" => "Kaleen 赞美工艺、艺术与伦理。我们制作定制的限量版地毯,从传统经典到大胆创新,旨在契合现代空间与美学。我们的灵感源自尼泊尔壮丽的自然景观与五行元素:火、水、土、风、金属。",
|
||||
"third" => "手工地毯长期以来一直是室内设计的核心,这一传统永不过时。在 Kaleen,我们自豪地以诚信与创意延续这一传承。我们的目标是建立强大的品牌形象,维护道德信誉,并拓展至全球高端市场。"
|
||||
]
|
||||
],
|
||||
"third" => [
|
||||
"title" => "我们的指导原则",
|
||||
"cards" => [
|
||||
"first" => [
|
||||
"title" => "我们的愿景",
|
||||
"desc" => "成为全球领先的奢华手工地毯品牌,以卓越品质、创新设计和可持续实践闻名。"
|
||||
],
|
||||
"second" => [
|
||||
"title" => "我们的使命",
|
||||
"desc" => "精心打造精美地毯,丰富人们的生活与空间,传承手工艺遗产,同时启发现代设计。"
|
||||
],
|
||||
"third" => [
|
||||
"title" => "我们的承诺",
|
||||
"desc" => "我们承诺卓越的工艺、道德采购与个性化服务,确保每一张 Kaleen 地毯都是永恒的艺术杰作。"
|
||||
]
|
||||
]
|
||||
],
|
||||
"fourth" => [
|
||||
"title" => "我们对质量与道德的承诺"
|
||||
]
|
||||
]
|
||||
],
|
||||
'product' => [
|
||||
'sections' => [
|
||||
'first' => [
|
||||
'title' => '我们的精美系列',
|
||||
'tab1' => '传统设计',
|
||||
'tab2' => '现代设计',
|
||||
'tab3' => '抽象设计'
|
||||
],
|
||||
'second' => [
|
||||
'title' => '地毯艺术:大师级的合作',
|
||||
'desc' => '探索我们与顶尖艺术家合作设计的独家地毯系列,其中包含施华洛世奇水晶等独特装饰元素。'
|
||||
]
|
||||
]
|
||||
],
|
||||
'bespoke' => [
|
||||
'sections' => [
|
||||
'banner' => [
|
||||
'title' => '您的愿景,我们的工艺',
|
||||
'subTitle' => '将您独特的想法转化为永恒的杰作'
|
||||
],
|
||||
'first' => [
|
||||
'title' => '我们的定制设计之旅',
|
||||
'card' => [
|
||||
'first' => [
|
||||
'title' => '展现您的愿景',
|
||||
'desc' => '分享您的灵感、房间尺寸和风格偏好。我们的设计顾问将帮助您将初步想法转化为具体概念,共同探讨色彩搭配、纹理和图案。'
|
||||
],
|
||||
'second' => [
|
||||
'title' => '精心绘制蓝图',
|
||||
'desc' => '从我们精美的材料系列中选择,如西藏羊毛、新西兰羊毛、纯丝或环保替代品。与我们的设计师合作敲定细节,并获得个性化的数字效果图。'
|
||||
],
|
||||
'third' => [
|
||||
'title' => '匠心创作过程',
|
||||
'desc' => '设计方案一经确认,您独特的设计便开始生动呈现。技艺精湛的工匠们运用代代相传的传统工艺,精心手工打结或手工织造您的地毯,确保每一根线都体现完美品质。'
|
||||
],
|
||||
'fourth' => [
|
||||
'title' => '最终润色与全球配送',
|
||||
'desc' => '每块定制地毯都经过严格的质量检查,以确保符合我们的高标准。确认无误后,您的定制杰作将被精心包装并安排运输,直接送达您的门前,随时准备为您的空间增添光彩。'
|
||||
]
|
||||
]
|
||||
],
|
||||
'second' => [
|
||||
'title' => '准备好创造您的杰作了吗?',
|
||||
"desc" => "我们的专业设计师和工匠团队随时准备将您的梦想地毯变成现实。",
|
||||
"desc2" => "
|
||||
立即与 Kaleen Carpets 一起开启您的定制之旅。",
|
||||
'button' => '开始定制您的地毯'
|
||||
]
|
||||
]
|
||||
],
|
||||
"contact" => [
|
||||
"sections" => [
|
||||
"first" => [
|
||||
"title" => "联系Kaleen地毯",
|
||||
"subTitle" => "我们在此为您提供任何咨询、定制设计需求或合作机会的帮助。",
|
||||
"subTitle2" => "通过我们的办事处或下方的联系表格与我们的团队取得联系。"
|
||||
],
|
||||
"second" => [
|
||||
"title" => "我们的全球办事处",
|
||||
"soorya" => [
|
||||
"title" => "Soorya地毯工业",
|
||||
"subTitle" => "我们的全球网络为您提供更好的服务。",
|
||||
"address" => "尼泊尔加德满都Thapathali-11 Swet Binayak Marg 2号 邮政信箱1765",
|
||||
"phone" => "[+977-1] 4780923, 4783003",
|
||||
"email" => "sooryacarpets@gmail.com"
|
||||
],
|
||||
"kaleen" => [
|
||||
"title" => "Kaleen展厅",
|
||||
"subTitle" => "我们的全球网络为您提供更好的服务。",
|
||||
"address" => "尼泊尔加德满都Babarmahal 11区 Kadel Chautari Prasuti Griha Marg",
|
||||
"phone" => "9802341880",
|
||||
"button" => "参观展厅"
|
||||
]
|
||||
],
|
||||
"third" => [
|
||||
"title" => "给我们发送消息",
|
||||
"subTitle" => "填写下面的表格,我们会尽快回复您。",
|
||||
"form" => [
|
||||
"name" => [
|
||||
"label" => "姓名",
|
||||
"input" => "请输入您的全名"
|
||||
],
|
||||
"email" => [
|
||||
"label" => "邮箱",
|
||||
"input" => "your.email@example.com"
|
||||
],
|
||||
"inquiry" => [
|
||||
"label" => "咨询类型",
|
||||
"input" => "请选择咨询类型"
|
||||
],
|
||||
"message" => [
|
||||
"label" => "消息内容",
|
||||
"input" => "请告诉我们您需要什么帮助"
|
||||
],
|
||||
"button" => "发送消息"
|
||||
]
|
||||
],
|
||||
"fourth" => [
|
||||
"title" => "直接联系",
|
||||
"desc" => "更倾向于直接与我们交谈或发送邮件?",
|
||||
"desc2" => "我们的团队随时准备为您提供帮助。",
|
||||
"callBtn" => "立即致电",
|
||||
"emailBtn" => "发送邮件"
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
];
|
||||
226
resources/lang/en/message.php
Normal file
226
resources/lang/en/message.php
Normal file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
return [
|
||||
"nav" => [
|
||||
"about-us" => "About Us",
|
||||
"art" => "Art of Weaving",
|
||||
"products" => "Our Products",
|
||||
"bespoke" => "Bespoke Design",
|
||||
"faq" => "FAQs",
|
||||
"contact" => "Contact Us"
|
||||
],
|
||||
"footer" => [
|
||||
"desc" => [
|
||||
"title" => "A beautiful home deserves beautiful carpets Since 1974, crafting the finest handmade Nepalese carpets.",
|
||||
"company" => "Soorya Carpet Industries",
|
||||
"address" => "Address: Thapathali, Kathmandu",
|
||||
"phone" => "Phone: [+977-1] 4780923, 4783003",
|
||||
"email" => "Email: sooryacarpets@gmail.com",
|
||||
],
|
||||
|
||||
"links" => [
|
||||
"home" => "Home",
|
||||
"contact" => "Contact Us",
|
||||
"about-us" => "About Us",
|
||||
"art" => "Art of Weaving",
|
||||
"products" => "Our Products",
|
||||
"bespoke" => "Bespoke Design",
|
||||
"gallery" => "Design Gallery / E-Catalog",
|
||||
"faq" => "FAQs",
|
||||
],
|
||||
"badges" => [
|
||||
"title" => "Certificates & Trust Badges"
|
||||
],
|
||||
"news" => [
|
||||
"title" => "Newsletter/Updates",
|
||||
"input" => "Email Address",
|
||||
"button" => "Subscribe",
|
||||
"legal" => [
|
||||
"title" => "Legal",
|
||||
"privacy" => "Privacy Policy",
|
||||
"terms" => "Terms & Conditions Return",
|
||||
"policy" => "Policy (from FAQ) Privacy Policy (from FAQ)"
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
"pages" => [
|
||||
"home" => [
|
||||
"banner" => [
|
||||
"title" => "A Beautiful Home Deserves A Beautiful Carpet",
|
||||
"subTitle" => "Carpets that are made with care from ground up",
|
||||
"button" => "Discover More"
|
||||
],
|
||||
"sections" => [
|
||||
"first" => [
|
||||
"title" => "Soorya Carpet",
|
||||
"desc" => "Discover the journey of Kaleen Carpets, a testament to enduring craftsmanship, innovative design, and a commitment to enriching lives through beautiful artistry.",
|
||||
"button" => "Learn More"
|
||||
],
|
||||
"second" => [
|
||||
"title" => "The Kaleen Rebrand",
|
||||
"desc" => "In 2015, Kaleen embarked on a transformative journey, evolving from a traditional manufacturer to a dynamic, luxury lifestyle brand.",
|
||||
"button" => "Learn More"
|
||||
],
|
||||
"third" => [
|
||||
"title" => "Art of Weaving",
|
||||
"desc" => "Since time immemorial, the art of carpet making has captured millions of carpet connoisseurs from around the world and still continues to do so.",
|
||||
"button" => "Learn More"
|
||||
],
|
||||
"testimonial" => [
|
||||
"title" => "Testimonials",
|
||||
"button" => "Give Your Testimonial"
|
||||
]
|
||||
]
|
||||
],
|
||||
"about" => [
|
||||
"sections" => [
|
||||
"first" => [
|
||||
"title" => "Our Story: Crafting Legacies Since 1974",
|
||||
"desc" => [
|
||||
"first" =>
|
||||
"The story of Soorya Carpet Industries begins in the early 1970s, when Mr. Laxman Shrestha and Mrs. Renuka Shrestha left their village in Dolakha and moved to Kathmandu with the ambition of building something meaningful. What started as a small rug-weaving initiative in a single room eventually grew into one of Nepal’s largest carpet manufacturing enterprises. Through perseverance and vision, they provided livelihoods to more than 1,000 skilled and unskilled workers and made a significant contribution to the country’s GDP. For over two decades, Soorya Carpet Industries earned international recognition, particularly in Germany, for exporting high-quality, hand-knotted carpets.",
|
||||
"second" => "
|
||||
By the late 1990s, however, Nepal’s carpet industry suffered severe setbacks owing to economic, social, and political challenges. Global scrutiny following child labour controversies in the wider industry, coupled with the instability caused by the Maoist insurgency, crippled the sector. Like many others, Soorya Carpet Industries was forced to scale down and eventually suspend production.",
|
||||
"third" => "
|
||||
The industry never quite returned to its early-1990s mass-scale export peak, yet it found ways to reinvent itself and stay relevant. Recognizing this shift, Soorya Carpet Industries transitioned from large-scale production to a boutique model, focusing on the niche luxury segment with custom-made, limited-edition rugs."
|
||||
]
|
||||
],
|
||||
"second" => [
|
||||
"title" => "The Kaleen Rebrand Story: A New Chapter",
|
||||
"desc" => [
|
||||
"first" => "Guided by the aspiration to create premium, ethical and artistic carpets, this journey led to the launch of Kaleen—our exclusive designer carpet brand.",
|
||||
"second" => "Kaleen celebrates craftsmanship, artistry, and ethics. We create bespoke, limited-edition rugs that range from time-honoured traditional designs to bold, innovative forms, all crafted to complement modern interiors and aesthetics. Our collections are inspired by beautiful landscapes of Nepal and the five elements of life: Fire, Water, Earth, Air, and Metal.",
|
||||
"third" => "Handmade carpets have long been central to interior design—a tradition that remains timeless. At Kaleen, we are proud to carry this heritage forward with integrity and creativity. Our ambition is to build a strong brand identity, uphold ethical credibility, and expand into discerning global markets."
|
||||
]
|
||||
],
|
||||
"third" => [
|
||||
"title" => "Our Guiding Principles",
|
||||
"cards" => [
|
||||
"first" => [
|
||||
"title" => "Our Vision",
|
||||
"desc" => "To be the global leader in luxury handcrafted carpets, renowned for unparalleled quality, innovative design, and sustainable practices."
|
||||
],
|
||||
"second" => [
|
||||
"title" => "Our Mission",
|
||||
"desc" => "To meticulously craft exquisite carpets that enrich lives and spaces, preserving artisanal heritage while inspiring contemporary design."
|
||||
],
|
||||
"third" => [
|
||||
"title" => "Our Promise",
|
||||
"desc" => "We promise exceptional artistry, ethical sourcing, and personalized service, ensuring every Kaleen carpet is a timeless masterpiece."
|
||||
]
|
||||
]
|
||||
],
|
||||
"fourth" => [
|
||||
"title" => "Our Commitment to Quality & Ethics"
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
"product" => [
|
||||
"sections" => [
|
||||
"first" => [
|
||||
"title" => "Our Exquisite Collections",
|
||||
"tab1" => "Traditional Design",
|
||||
"tab2" => "Modern Design",
|
||||
"tab3" => "Abstract Design"
|
||||
],
|
||||
"second" => [
|
||||
"title" => "Art in Carpet: Masterful Collaborations",
|
||||
"desc" => "Explore our exclusive collection of carpets designed in partnership with leading artists and featuring unique embellishments like Swarovski crystals."
|
||||
]
|
||||
]
|
||||
],
|
||||
"bespoke" => [
|
||||
"sections" => [
|
||||
"banner" => [
|
||||
"title" => "Your Vision, Our Craft",
|
||||
"subTitle" => "Transforming your unique ideas into a timeless masterpiece"
|
||||
],
|
||||
"first" => [
|
||||
"title" => "Our Bespoke Design Journey",
|
||||
"card" => [
|
||||
"first" => [
|
||||
"title" => "Your Vision Unveiled",
|
||||
"desc" => "Share your inspirations, room dimensions, and style preferences. Our design consultants will help translate your initial ideas into a tangible concept, discussing color palettes, textures, and patterns."
|
||||
],
|
||||
"second" => [
|
||||
"title" => "Crafting the Blueprint",
|
||||
"desc" => "Choose from our exquisite range of materials like Tibetan wool, New Zealand wool, pure silk, or eco-friendly alternatives. Collaborate with our designers to finalize the intricate details and receive a personalized digital rendering."
|
||||
],
|
||||
"third" => [
|
||||
"title" => "The Art of Creation",
|
||||
"desc" => "Once approved, your unique design comes to life. Skilled artisans meticulously hand-knot or hand-loom your rug, employing time-honored techniques passed down through generations, ensuring every thread embodies perfection."
|
||||
],
|
||||
"fourth" => [
|
||||
"title" => "Final Touches & Global Delivery",
|
||||
"desc" => "Each custom rug undergoes rigorous quality checks to meet our exacting standards. After approval, your bespoke masterpiece is carefully prepared and shipped, arriving directly at your doorstep, ready to transform your space."
|
||||
]
|
||||
]
|
||||
],
|
||||
"second" => [
|
||||
"title" => "Ready to Create Your Masterpiece?",
|
||||
"desc" => "Our team of expert designers and artisans is ready to bring your dream rug to life.",
|
||||
"desc2" => "
|
||||
Start your bespoke journey with Kaleen Carpets today.",
|
||||
"button" => "Start Your Custom Rug"
|
||||
]
|
||||
]
|
||||
],
|
||||
"contact" => [
|
||||
"sections" => [
|
||||
"first" => [
|
||||
"title" => "Connect with Kaleen Carpets",
|
||||
"subTitle" => "We are here to assist you with any inquiries, bespoke design requests, or partnership opportunities.",
|
||||
"subTitle2" => "Reach out to our team through our offices or the contact form below."
|
||||
],
|
||||
"second" => [
|
||||
"title" => "Our Global Office",
|
||||
"soorya" => [
|
||||
"title" => "Soorya Carpet Industries",
|
||||
"subTitle" => "Our global presence to serve you better.",
|
||||
"address" => "G.P.O Box 1765 2 Swet Binayak Marg Thapathali -11, Kathmandu, Nepal",
|
||||
"phone" => "[+977-1] 4780923, 4783003",
|
||||
"email" => "sooryacarpets@gmail.com"
|
||||
],
|
||||
"kaleen" => [
|
||||
"title" => "Kaleen Studio",
|
||||
"subTitle" => "Our global presence to serve you better.",
|
||||
"address" => "Kadel Chautari Prasuti Griha Marg Ward No. 11, Babarmahal Kathmandu, Nepal",
|
||||
"phone" => "9802341880",
|
||||
"button" => "Visit Studio"
|
||||
]
|
||||
],
|
||||
"third" => [
|
||||
"title" => "Send us a Message",
|
||||
"subTitle" => "Fill our the form below and we'll get back to you as soon as possible.",
|
||||
"form" => [
|
||||
"name" => [
|
||||
"label" => "Name",
|
||||
"input" => "Full Name"
|
||||
],
|
||||
"email" => [
|
||||
"label" => "Email",
|
||||
"input" => "your.email@example.com"
|
||||
],
|
||||
"inquiry" => [
|
||||
"label" => "Inquiry",
|
||||
"input" => "Select an inquiry type"
|
||||
],
|
||||
"message" => [
|
||||
"label" => "Message",
|
||||
"input" => "Tell us how can we help you"
|
||||
],
|
||||
"button" => "Send Message"
|
||||
]
|
||||
],
|
||||
"fourth" => [
|
||||
"title" => "Direct Engagement",
|
||||
"desc" => "Prefer to speak with us directly or send a quick email?",
|
||||
"desc2" => "Our team is ready to assist.",
|
||||
"callBtn" => "Call Us Now",
|
||||
"emailBtn" => "Email Our Team"
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
];
|
||||
@@ -1,49 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @class(['dark' => ($appearance ?? 'system') == 'dark'])>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
{{-- Inline script to detect system dark mode preference and apply it immediately --}}
|
||||
<script>
|
||||
(function() {
|
||||
const appearance = '{{ $appearance ?? "system" }}';
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
if (appearance === 'system') {
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
{{-- Inline script to detect system dark mode preference and apply it immediately --}}
|
||||
<script>
|
||||
(function() {
|
||||
const appearance = '{{ $appearance ?? 'system' }}';
|
||||
|
||||
if (prefersDark) {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
if (appearance === 'system') {
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
|
||||
if (prefersDark) {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
{{-- Inline style to set the HTML background color based on our theme in app.css --}}
|
||||
<style>
|
||||
html {
|
||||
background-color: oklch(1 0 0);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
html.dark {
|
||||
background-color: oklch(0.145 0 0);
|
||||
}
|
||||
</style>
|
||||
{{-- Inline style to set the HTML background color based on our theme in app.css --}}
|
||||
<style>
|
||||
html {
|
||||
background-color: oklch(1 0 0);
|
||||
}
|
||||
|
||||
<title inertia>{{ config('app.name', 'Laravel') }}</title>
|
||||
html.dark {
|
||||
background-color: oklch(0.145 0 0);
|
||||
}
|
||||
</style>
|
||||
|
||||
<link rel="icon" href="/favicon.ico" sizes="any">
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||
<title inertia>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" />
|
||||
<link rel="icon" href="/favicon.png" sizes="any">
|
||||
<link rel="icon" href="/favicon.png" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="/favicon.png">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" />
|
||||
|
||||
@viteReactRefresh
|
||||
@vite(['resources/js/app.tsx', "resources/js/pages/{$page['component']}.tsx"])
|
||||
@inertiaHead
|
||||
</head>
|
||||
|
||||
<body class="font-sans antialiased">
|
||||
@inertia
|
||||
</body>
|
||||
|
||||
@viteReactRefresh
|
||||
@vite(['resources/js/app.tsx', "resources/js/pages/{$page['component']}.tsx"])
|
||||
@inertiaHead
|
||||
</head>
|
||||
<body class="font-sans antialiased">
|
||||
@inertia
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
use App\Http\Controllers\Auth\DashboardController;
|
||||
use App\Http\Controllers\Client\AboutController;
|
||||
use App\Http\Controllers\Client\HomeController;
|
||||
use App\Http\Controllers\client\ProductController;
|
||||
use App\Http\Controllers\Client\TestimonialController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Inertia\Inertia;
|
||||
|
||||
@@ -12,7 +14,22 @@ Route::get('/about-us', [AboutController::class, 'index'])->name('about');
|
||||
Route::get('/art-of-weaving', [HomeController::class, 'art'])->name('artOfWeaving');
|
||||
Route::get('/contact', [HomeController::class, 'contact'])->name('contact');
|
||||
Route::get('/faq', [HomeController::class, 'faq'])->name('faq');
|
||||
Route::get('/product', [HomeController::class, 'product'])->name('product');
|
||||
Route::get('/product', [HomeController::class, 'product'])->name('index.product');
|
||||
Route::get('/gallery', [HomeController::class, 'gallery'])->name('gallery');
|
||||
Route::get('/bespoke', [HomeController::class, 'bespoke'])->name('bespoke');
|
||||
|
||||
Route::post('/locale', function (Request $request) {
|
||||
$request->validate([
|
||||
'locale' => 'required|in:en,cn'
|
||||
]);
|
||||
|
||||
$locale = $request->input('locale');
|
||||
|
||||
Session::put('locale', $locale);
|
||||
// App::setLocale($locale);
|
||||
|
||||
return redirect()->back();
|
||||
})->name('locale.change');
|
||||
|
||||
Route::get('/testimonial', [TestimonialController::class, 'index'])->name('testimonial.index');
|
||||
Route::post('/testimonial', [TestimonialController::class, 'store'])->name('testimonial.store');
|
||||
@@ -21,6 +38,11 @@ Route::post('/testimonial', [TestimonialController::class, 'store'])->name('test
|
||||
Route::middleware(['auth', 'verified'])->name("dashboard.")->group(function () {
|
||||
Route::get('/dashboard', [DashboardController::class, 'index'])->name('index');
|
||||
|
||||
|
||||
Route::get('/product/dashboard', [ProductController::class, 'index'])->name('product.index');
|
||||
Route::get('/product/add', [ProductController::class, 'productAdd'])->name('product.add');
|
||||
Route::post('/product/add', [ProductController::class, 'productAddPost'])->name('product.add.post');
|
||||
|
||||
Route::get('/carousel', [DashboardController::class, 'carousel'])->name('carousel.index');
|
||||
Route::get('/carousel/add', [DashboardController::class, 'carouselAdd'])->name('carousel.add');
|
||||
Route::post('/carousel', [DashboardController::class, 'carouselStore'])->name('carousel.store');
|
||||
|
||||
Reference in New Issue
Block a user