added Karen theme part

improved ux of preview QuantitiesAddToCard
pull/49/head
A1Gard 3 months ago
parent 1d4622f270
commit 5328c33b34

@ -99,6 +99,9 @@ export default {
methods: { methods: {
select(i) { select(i) {
document.querySelector('#price').innerText = commafy(this.qz[i].price.toString()) + ' ' + this.currency; document.querySelector('#price').innerText = commafy(this.qz[i].price.toString()) + ' ' + this.currency;
let index = this.qz[i].image;
document.querySelector('#preview a').setAttribute('href',document.querySelector(`#hidden-images a:nth-child(${index+1})`).getAttribute('href'));
document.querySelector('#preview img').setAttribute('src',document.querySelector(`#hidden-images a:nth-child(${index+1}) img`).getAttribute('src'));
this.selected = i; this.selected = i;
}, },
async add2card() { async add2card() {

@ -20,10 +20,12 @@
</nav> </nav>
<div class="row"> <div class="row">
<div class="col-lg-5"> <div class="col-lg-5">
<div id="preview">
<a href="{{$product->originalImageUrl()}}" id="aria-main-img" class="light-box" <a href="{{$product->originalImageUrl()}}" id="aria-main-img" class="light-box"
data-gallery="aria-products"> data-gallery="aria-products">
<img src="{{$product->originalImageUrl()}}" alt="{{$product->name}}"> <img src="{{$product->originalImageUrl()}}" alt="{{$product->name}}">
</a> </a>
</div>
<div id="aria-img-slider"> <div id="aria-img-slider">
@foreach($product->getMedia() as $media) @foreach($product->getMedia() as $media)
<div class="item"> <div class="item">
@ -132,7 +134,8 @@
<div class="accordion mt-4" id="product-detail"> <div class="accordion mt-4" id="product-detail">
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header"> <h2 class="accordion-header">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#desc" aria-expanded="true" <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#desc"
aria-expanded="true"
aria-controls="desc"> aria-controls="desc">
{{__("Description")}} {{__("Description")}}
</button> </button>
@ -147,7 +150,8 @@
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header"> <h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#table" <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
data-bs-target="#table"
aria-expanded="false" aria-controls="table"> aria-expanded="false" aria-controls="table">
{{__("Product table")}} {{__("Product table")}}
</button> </button>
@ -161,7 +165,8 @@
@endif @endif
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header"> <h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#info" aria-expanded="false" aria-controls="info"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
data-bs-target="#info" aria-expanded="false" aria-controls="info">
{{__("Information")}} {{__("Information")}}
</button> </button>
</h2> </h2>

@ -4,6 +4,8 @@ import {tns} from "tiny-slider/src/tiny-slider";
var ariaImgSlider, ariaRelativeSlider; var ariaImgSlider, ariaRelativeSlider;
document.addEventListener('DOMContentLoaded',function () { document.addEventListener('DOMContentLoaded',function () {
for (const el of document.querySelectorAll('.light-box')) { for (const el of document.querySelectorAll('.light-box')) {
el.addEventListener('click', Lightbox.initialize); el.addEventListener('click', Lightbox.initialize);
} }

@ -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">&nbsp;</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>
&nbsp;
{{$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…
Cancel
Save