mirror of https://github.com/4xmen/xshop.git
parent
1d4622f270
commit
5328c33b34
@ -0,0 +1,204 @@
|
|||||||
|
<section id='ProductKaren' class="content">
|
||||||
|
|
||||||
|
<div class="{{gfx()['container']}}">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<div id="preview">
|
||||||
|
<a href="{{$product->originalImageUrl()}}" id="karen-main-img" class="light-box"
|
||||||
|
data-gallery="karen-products">
|
||||||
|
<img src="{{$product->originalImageUrl()}}" alt="{{$product->name}}">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div id="karen-img-slider">
|
||||||
|
@foreach($product->getMedia() as $media)
|
||||||
|
<div class="item">
|
||||||
|
<a href="{{$media->getUrl('product-image')}}">
|
||||||
|
<img src="{{$media->getUrl('product-image')}}" alt="{{$product->name}}">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-7" id="karen-product-detail">
|
||||||
|
<nav aria-label="breadcrumb" class="pt-1">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li class="breadcrumb-item">
|
||||||
|
<a href="{{homeUrl()}}">
|
||||||
|
{{config('app.name')}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="breadcrumb-item">
|
||||||
|
<a href="{{$product->category->webUrl()}}">
|
||||||
|
{{$product->category->name}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">
|
||||||
|
{{$product->name}}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
{{$product->name}}
|
||||||
|
</h1>
|
||||||
|
<div class="description">
|
||||||
|
<p>
|
||||||
|
{{$product->excerpt}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div id="price" class="col">
|
||||||
|
{{$product->getPrice()}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($product->hasDiscount())
|
||||||
|
<div id="price-old" class="col">
|
||||||
|
{{$product->oldPrice()}}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@if($product->sku != null && $product->sku != '')
|
||||||
|
<div class="karen-product-data">
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{__("SKU")}}:
|
||||||
|
</span>
|
||||||
|
<b>
|
||||||
|
{{$product->sku}}
|
||||||
|
</b>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if($product->categories()->count() > 0)
|
||||||
|
<div class="karen-product-data">
|
||||||
|
<span>
|
||||||
|
{{__("Categories")}}:
|
||||||
|
</span>
|
||||||
|
@foreach($product->categories()->where('id','<>',$product->category->id)->get() as $cat)
|
||||||
|
<a href="{{$cat->webUrl()}}">
|
||||||
|
{{$cat->name}},
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
<a href="{{$product->category->webUrl()}}">
|
||||||
|
{{$product->category->name}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if($product->tags()->count() > 0)
|
||||||
|
<div class="karen-product-data">
|
||||||
|
<span>
|
||||||
|
{{__("Tags")}}:
|
||||||
|
</span>
|
||||||
|
@foreach($product->tags as $tag)
|
||||||
|
<a href="{{tagUrl($tag->slug)}}" class="tag me-2">
|
||||||
|
<i class="ri-price-tag-line"></i>
|
||||||
|
{{$tag->name}}
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<br>
|
||||||
|
<a class="fav-btn" data-slug="{{$product->slug}}" data-is-fav="{{$product->isFav()}}">
|
||||||
|
<i class="ri-heart-line me-3"></i>
|
||||||
|
<i class="ri-heart-fill me-3"></i>
|
||||||
|
{{__("Toggle favorite")}}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="mx-2 compare-btn" data-slug="{{$product->slug}}">
|
||||||
|
<i class="ri-scales-3-line me-3"></i>
|
||||||
|
{{__("Add to compare list")}}
|
||||||
|
</a>
|
||||||
|
<div class="mt-1"> </div>
|
||||||
|
|
||||||
|
@if($product->quantities()->count()>0)
|
||||||
|
<quantities-add-to-card
|
||||||
|
:qz='@json($product->quantities)'
|
||||||
|
:props='@json(usableProp($product->category->props))'
|
||||||
|
currency="{{config('app.currency.symbol')}}"
|
||||||
|
card-link="{{ route('client.product-card-toggle',$product->slug) }}"
|
||||||
|
|
||||||
|
@if($product->hasDiscount())
|
||||||
|
:discount='@json($product->activeDiscounts()->first())'
|
||||||
|
@endif
|
||||||
|
></quantities-add-to-card>
|
||||||
|
@else
|
||||||
|
<a href="{{ route('client.product-card-toggle',$product->slug) }}"
|
||||||
|
class="btn btn-outline-primary add-to-card btn-lg">
|
||||||
|
<i class="ri-shopping-bag-3-line"></i>
|
||||||
|
{{__("Add to card")}}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="navtabs">
|
||||||
|
<div class="navtab active" data-target="desc">
|
||||||
|
{{__("Description")}}
|
||||||
|
</div>
|
||||||
|
@if($product->table != null || trim($product->table) != '')
|
||||||
|
<div class="navtab" data-target="table">
|
||||||
|
{{__("Product table")}}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="navtab" data-target="info">
|
||||||
|
{{__("Information")}}
|
||||||
|
</div>
|
||||||
|
<div class="underline"></div>
|
||||||
|
</div>
|
||||||
|
<div id="desc" class="tab-content active">
|
||||||
|
{!! $product->description !!}
|
||||||
|
</div>
|
||||||
|
<div id="table" class="tab-content">
|
||||||
|
{!! $product->table !!}
|
||||||
|
</div>
|
||||||
|
<div id="info" class="tab-content">
|
||||||
|
<table class="table table-striped table-bordered table-striped">
|
||||||
|
<tr>
|
||||||
|
<th class="w-50">
|
||||||
|
{{__("Item")}}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{__("Value")}}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
@foreach($product->fullMeta() as $meta)
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<i class="{{$meta['data']->icon}}"></i>
|
||||||
|
|
||||||
|
{{$meta['data']->label}}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
{!! $meta['human_value'] !!}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<h3 class="mt-4">
|
||||||
|
{{__("Related products")}}
|
||||||
|
</h3>
|
||||||
|
<div id="rel-products">
|
||||||
|
@foreach($product->category->products()->where('status',1)->limit(10)->get() as $p)
|
||||||
|
<div class="item">
|
||||||
|
<div class="karen-product-list">
|
||||||
|
<a href="{{$p->imgUrl()}}">
|
||||||
|
<img src="{{$p->imgUrl()}}" alt="{{$p->name}}">
|
||||||
|
<h5>
|
||||||
|
{{$p->name}}
|
||||||
|
</h5>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="hidden-images">
|
||||||
|
@foreach($product->getMedia() as $k => $media)
|
||||||
|
<a href="{{$media->getUrl()}}" class="light-box"
|
||||||
|
data-gallery="karen-products">
|
||||||
|
<img src="{{$media->getUrl('product-image')}}" id="hidden-img-{{$k}}"
|
||||||
|
alt="{{$product->name}}">
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</section>
|
@ -0,0 +1,93 @@
|
|||||||
|
import Lightbox from 'bs5-lightbox' ;
|
||||||
|
import {tns} from "tiny-slider/src/tiny-slider";
|
||||||
|
|
||||||
|
var karenImgSlider, karenRelativeSlider;
|
||||||
|
document.addEventListener('DOMContentLoaded',function () {
|
||||||
|
|
||||||
|
for (const el of document.querySelectorAll('.light-box')) {
|
||||||
|
el.addEventListener('click', Lightbox.initialize);
|
||||||
|
}
|
||||||
|
karenImgSlider = tns({
|
||||||
|
container: '#karen-img-slider',
|
||||||
|
items: 3,
|
||||||
|
autoplay: true,
|
||||||
|
autoplayButton: false,
|
||||||
|
// nextButton: false,
|
||||||
|
controls: false,
|
||||||
|
autoplayHoverPause: true,
|
||||||
|
mouseDrag: true,
|
||||||
|
gutter: 5,
|
||||||
|
slideBy: 1,
|
||||||
|
autoplayTimeout: 5000,
|
||||||
|
// speed:10000,
|
||||||
|
});
|
||||||
|
karenRelativeSlider = tns({
|
||||||
|
container: '#rel-products',
|
||||||
|
items: 3,
|
||||||
|
autoplay: true,
|
||||||
|
autoplayButton: false,
|
||||||
|
// nextButton: false,
|
||||||
|
controls: false,
|
||||||
|
autoplayHoverPause: true,
|
||||||
|
mouseDrag: true,
|
||||||
|
gutter: 5,
|
||||||
|
slideBy: 1,
|
||||||
|
autoplayTimeout: 5000,
|
||||||
|
responsive:{
|
||||||
|
560:{
|
||||||
|
items: 1,
|
||||||
|
},
|
||||||
|
768:{
|
||||||
|
items: 2,
|
||||||
|
},
|
||||||
|
1000:{
|
||||||
|
items: 4,
|
||||||
|
},
|
||||||
|
1400:{
|
||||||
|
items: 5,
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
// speed:10000,
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('#karen-img-slider a')?.forEach(function (el) {
|
||||||
|
el.addEventListener('click',function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
document.querySelector('#karen-main-img').setAttribute('href',el.getAttribute('href'));
|
||||||
|
document.querySelector('#karen-main-img img').setAttribute('src',el.querySelector('img').getAttribute('src'));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// tabs
|
||||||
|
const tabs = document.querySelectorAll('.navtab');
|
||||||
|
const contents = document.querySelectorAll('.tab-content');
|
||||||
|
const underline = document.querySelector('.underline');
|
||||||
|
|
||||||
|
function updateUnderline() {
|
||||||
|
const activeTab = document.querySelector('.navtab.active');
|
||||||
|
underline.style.width = `${activeTab.offsetWidth}px`;
|
||||||
|
underline.style.left = `${activeTab.offsetLeft}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabs.forEach(tab => {
|
||||||
|
tab.addEventListener('click', () => {
|
||||||
|
tabs.forEach(t => t.classList.remove('active'));
|
||||||
|
tab.classList.add('active');
|
||||||
|
const target = tab.getAttribute('data-target');
|
||||||
|
contents.forEach(content => {
|
||||||
|
if (content.id === target) {
|
||||||
|
content.classList.add('active');
|
||||||
|
} else {
|
||||||
|
content.classList.remove('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateUnderline();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('resize', updateUnderline);
|
||||||
|
updateUnderline();
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "ProductKaren",
|
||||||
|
"version": "1.0",
|
||||||
|
"author": "xStack",
|
||||||
|
"email": "xshop@xstack.ir",
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"url": "https:\/\/xstack.ir",
|
||||||
|
"author_url": "https:\/\/4xmen.ir",
|
||||||
|
"packages": []
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Resources\Views\Segments;
|
||||||
|
|
||||||
|
use App\Models\Part;
|
||||||
|
use App\Models\Setting;
|
||||||
|
|
||||||
|
class ProductKaren
|
||||||
|
{
|
||||||
|
public static function onAdd(Part $part = null)
|
||||||
|
{
|
||||||
|
$setting = new Setting();
|
||||||
|
$setting->section = 'theme';
|
||||||
|
$setting->key = $part->area->name . '_' . $part->part.'_bg';
|
||||||
|
$setting->value = '#ffffff';
|
||||||
|
$setting->type = 'COLOR';
|
||||||
|
$setting->data = json_encode(['name' => 'karen-tab-bg-color']);
|
||||||
|
$setting->size = 12;
|
||||||
|
$setting->title = $part->area->name . ' ' . $part->part .' tab background color';
|
||||||
|
$setting->save();
|
||||||
|
}
|
||||||
|
public static function onRemove(Part $part = null)
|
||||||
|
{
|
||||||
|
Setting::where('key',$part->area->name . '_' . $part->part.'_bg')->first()?->delete();
|
||||||
|
}
|
||||||
|
public static function onMount(Part $part = null)
|
||||||
|
{
|
||||||
|
return $part;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
#ProductKaren {
|
||||||
|
padding: 1rem 0;
|
||||||
|
|
||||||
|
|
||||||
|
#preview{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#karen-product-detail{
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.description{
|
||||||
|
//border: 1px solid var(--xshop-primary);
|
||||||
|
//border-radius: var(--xshop-border-radius);
|
||||||
|
padding: 1rem 0;
|
||||||
|
p{
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1{
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
#price{
|
||||||
|
color: var(--xshop-primary);
|
||||||
|
font-size: 27px;
|
||||||
|
margin-bottom: .7rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#price-old{
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: line-through red;
|
||||||
|
font-size: 27px;
|
||||||
|
color: gray;
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-btn, .compare-btn {
|
||||||
|
|
||||||
|
height: 40px;
|
||||||
|
background: #ffffff55;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: var(--xshop-border-radius);
|
||||||
|
z-index: 4;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: .4s;
|
||||||
|
padding:7px 1rem;
|
||||||
|
border: 1px solid var(--xshop-primary);
|
||||||
|
i{
|
||||||
|
font-size: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--xshop-primary);
|
||||||
|
color: var(--xshop-diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fav-btn {
|
||||||
|
top: calc(3% + 50px);
|
||||||
|
|
||||||
|
&[data-is-fav="-1"]{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&[data-is-fav="1"]{
|
||||||
|
.ri-heart-line{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&[data-is-fav="0"]{
|
||||||
|
.ri-heart-fill{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p{
|
||||||
|
text-align: justify;
|
||||||
|
color: gray;
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#karen-main-img{
|
||||||
|
img{
|
||||||
|
height: 50vh;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: var(--xshop-border-radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#karen-img-slider{
|
||||||
|
margin-top: 5px;
|
||||||
|
img{
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: var(--xshop-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.karen-product-data{
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.karen-product-list{
|
||||||
|
padding: 5px;
|
||||||
|
img{
|
||||||
|
height: 20vh;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: var(--xshop-border-radius);
|
||||||
|
}
|
||||||
|
h5{
|
||||||
|
text-align: center;
|
||||||
|
padding: .5rem 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.navtabs {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
background: var(--karen-tab-bg-color,#ffffff);
|
||||||
|
box-shadow: var(--xshop-shadow);
|
||||||
|
border-radius: var(--xshop-border-radius);
|
||||||
|
padding: 10px 20px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.navtab {
|
||||||
|
margin: 0 10px;
|
||||||
|
padding: 5px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.3s;
|
||||||
|
&:hover {
|
||||||
|
color: var(--xshop-secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navtab.active {
|
||||||
|
color: var(--xshop-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.underline {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--xshop-primary);
|
||||||
|
transition: left 0.3s ease, width 0.3s ease;
|
||||||
|
}
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
padding: 1rem;
|
||||||
|
background: var(--karen-tab-bg-color,#ffffff);
|
||||||
|
}
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 438 KiB |
Loading…
Reference in New Issue