wip: cart

This commit is contained in:
Nikita Kiselev
2025-07-20 22:22:14 +03:00
parent 1ffb1cef12
commit ee67bd55df
12 changed files with 541 additions and 19 deletions

View File

@@ -0,0 +1,93 @@
<template>
<div
v-if="logs.length"
ref="logContainer"
class="fixed bottom-0 left-0 right-0 max-h-60 overflow-y-auto bg-white text-sm font-mono border-t border-gray-300 shadow-lg z-[9999] p-4 space-y-2"
>
<div
v-for="(log, idx) in logs"
:key="idx"
:class="colorClass(log.type)"
class="whitespace-pre-wrap"
>
[{{ log.type.toUpperCase() }}] {{ log.message }}
</div>
</div>
</template>
<script setup>
import {ref, onMounted, nextTick} from 'vue'
const logs = ref([])
const logContainer = ref(null)
function pushLog(type, input) {
let message = ''
let details = ''
if (input instanceof Error) {
message = input.message
details = input.stack
} else if (typeof input === 'string') {
message = input
} else {
try {
message = JSON.stringify(input, null, 2)
} catch {
message = String(input)
}
}
logs.value.push({ type, message, details })
nextTick(() => {
const el = logContainer.value
if (el) el.scrollTop = el.scrollHeight
});
}
function colorClass(type) {
switch (type) {
case 'error': return 'text-red-700'
case 'warn': return 'text-yellow-700'
case 'info': return 'text-blue-700'
default: return 'text-gray-800'
}
}
onMounted(() => {
if (import.meta.env.PROD) return
// Backup originals
const orig = {
log: console.log,
warn: console.warn,
error: console.error,
info: console.info,
}
Object.entries(orig).forEach(([type, fn]) => {
console[type] = (...args) => {
pushLog(type, args.map(toText).join(' '))
fn.apply(console, args)
}
})
window.addEventListener('error', (e) => {
pushLog('error', e.error?.stack || `${e.message} at ${e.filename}:${e.lineno}:${e.colno}`)
})
window.addEventListener('unhandledrejection', (e) => {
pushLog('error', e.reason?.stack || e.reason?.message || String(e.reason))
})
})
function toText(v) {
try {
if (typeof v === 'string') return v
return JSON.stringify(v, null, 2)
} catch {
return String(v)
}
}
</script>

View File

@@ -0,0 +1,74 @@
<template>
<swiper
:style="{
'--swiper-navigation-color': '#fff',
'--swiper-pagination-color': '#fff',
}"
:lazy="true"
:pagination="pagination"
:navigation="true"
:modules="modules"
class="mySwiper"
>
<swiper-slide v-for="image in images">
<img
:src="image.url"
:alt="image.alt"
loading="lazy"
/>
<div
class="swiper-lazy-preloader swiper-lazy-preloader-white"
></div>
</swiper-slide>
</swiper>
</template>
<script>
import {Swiper, SwiperSlide} from 'swiper/vue';
import 'swiper/css';
import 'swiper/css/pagination';
import {Pagination} from 'swiper/modules';
export default {
components: {
Swiper,
SwiperSlide,
},
props: {
images: {
type: Array,
default: () => [],
}
},
setup() {
return {
pagination: {
clickable: true,
dynamicBullets: true,
},
modules: [Pagination],
};
},
};
</script>
<style scoped>
.product-swiper {
width: 100%;
height: auto;
}
.swiper-slide {
text-align: center;
}
img {
width: 100%;
display: block;
object-fit: contain;
}
</style>