fix: style
This commit is contained in:
@@ -1,10 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Default || 'div'">
|
<component :is="Default || 'div'">
|
||||||
<p class="cursor-pointer" @click="backFromProduct()">Back to products</p>
|
<div class="flex items-center gap-2 mb-4">
|
||||||
<div class="container my-10 mx-auto ">
|
<UIcon name="line-md:arrow-left" class="text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
|
||||||
|
<p class="cursor-pointer text-(--accent-blue-light) dark:text-(--accent-blue-dark)" @click="backFromProduct()">
|
||||||
|
Back to products</p>
|
||||||
|
</div>
|
||||||
|
<div class="container mx-auto ">
|
||||||
<div
|
<div
|
||||||
class=" gap-4 mb-6 bg-(--second-light) dark:bg-(--main-dark) border border-(--border-light) dark:border-(--border-dark) p-4 rounded-md">
|
class=" gap-4 mb-6 bg-(--second-light) dark:bg-(--main-dark) border border-(--border-light) dark:border-(--border-dark) p-4 rounded-md">
|
||||||
<div v-if="!isShowProductView" class="flex items-end justify-between">
|
<div v-if="!isShowProductView" class="flex items-center justify-between">
|
||||||
<div class="flex items-center gap-3" v-if="!isTranslations">
|
<div class="flex items-center gap-3" v-if="!isTranslations">
|
||||||
<p class="text-red-500 text-md whitespace-nowrap">Translate from Polish to</p>
|
<p class="text-red-500 text-md whitespace-nowrap">Translate from Polish to</p>
|
||||||
<USelect v-model="toLangId" :items="availableLangs" value-key="id" label-key="name"
|
<USelect v-model="toLangId" :items="availableLangs" value-key="id" label-key="name"
|
||||||
@@ -21,7 +25,7 @@
|
|||||||
</USelect>
|
</USelect>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-3 items-end justify-end">
|
<div class="flex gap-3">
|
||||||
<UButton @click="() => {
|
<UButton @click="() => {
|
||||||
fetchForLanguage(toLangId)
|
fetchForLanguage(toLangId)
|
||||||
isShowProductView = true
|
isShowProductView = true
|
||||||
@@ -34,7 +38,7 @@
|
|||||||
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) px-12!">
|
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) px-12!">
|
||||||
Translate
|
Translate
|
||||||
</UButton>
|
</UButton>
|
||||||
<div v-else class="flex gap-3 items-end justify-end">
|
<div v-else class="flex gap-3">
|
||||||
<UButton @click="() => {
|
<UButton @click="() => {
|
||||||
toLangId = settingStore.shopDefaultLanguage
|
toLangId = settingStore.shopDefaultLanguage
|
||||||
isTranslations = false
|
isTranslations = false
|
||||||
@@ -50,7 +54,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<UButton @click="isShowProductView = false" color="primary"
|
<UButton @click="isShowProductView = false" color="primary"
|
||||||
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) px-12!">
|
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) gap-2">
|
||||||
|
<UIcon name="line-md:arrow-left" class="" />
|
||||||
Back
|
Back
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -162,7 +167,6 @@ import Default from '@/layouts/default.vue';
|
|||||||
import { langs } from '@/router/langs';
|
import { langs } from '@/router/langs';
|
||||||
import { useProductStore } from '@/stores/product';
|
import { useProductStore } from '@/stores/product';
|
||||||
import { useSettingsStore } from '@/stores/settings';
|
import { useSettingsStore } from '@/stores/settings';
|
||||||
import { watch } from 'vue';
|
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
@@ -226,6 +230,8 @@ const translateToSelectedLanguage = async () => {
|
|||||||
const fetchForLanguage = async (langId: number | null) => {
|
const fetchForLanguage = async (langId: number | null) => {
|
||||||
if (productID.value) {
|
if (productID.value) {
|
||||||
await productStore.getProductDescription(langId, productID.value)
|
await productStore.getProductDescription(langId, productID.value)
|
||||||
|
removeInlineStylesFromAll(productStore.productDescription)
|
||||||
|
removePStyles(productStore.productDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +243,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// text edit
|
// text edit
|
||||||
const enableEdit = () => {
|
const enableEdit = () => {
|
||||||
if (usageRef.value) {
|
if (usageRef.value) {
|
||||||
@@ -290,4 +297,48 @@ const cancelDescriptionEdit = () => {
|
|||||||
}
|
}
|
||||||
descriptionEdit.disableEdit()
|
descriptionEdit.disableEdit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeInlineStylesFromAll(product) {
|
||||||
|
if (!product) return
|
||||||
|
const removeStyles = (html: string) => {
|
||||||
|
if (!html) return ''
|
||||||
|
const div = document.createElement('div')
|
||||||
|
div.innerHTML = html
|
||||||
|
|
||||||
|
div.querySelectorAll('*').forEach(el => {
|
||||||
|
const bg = el.style.background || el.style.backgroundColor
|
||||||
|
if (bg) {
|
||||||
|
el.style.background = ''
|
||||||
|
el.style.backgroundColor = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
div.querySelectorAll('p').forEach(p => {
|
||||||
|
if (p.querySelector('img')) {
|
||||||
|
p.style.display = 'flex'
|
||||||
|
p.style.gap = '20px'
|
||||||
|
p.style.padding = '30px 0'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
div.querySelectorAll('table').forEach(table => {
|
||||||
|
table.querySelectorAll('tbody').forEach(tbody => {
|
||||||
|
tbody.style.setProperty('background-color', 'white', 'important')
|
||||||
|
tbody.querySelectorAll('tr').forEach(tr => {
|
||||||
|
tr.querySelectorAll('td').forEach(td => {
|
||||||
|
td.style.setProperty('padding', '10px', 'important')
|
||||||
|
td.querySelectorAll('p').forEach(p => {
|
||||||
|
p.style.setProperty('display', 'flex', 'important')
|
||||||
|
p.style.setProperty('padding', '0px', 'important')
|
||||||
|
p.style.setProperty('align-items', 'start', 'important')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return div.innerHTML
|
||||||
|
}
|
||||||
|
product.description = removeStyles(product.description)
|
||||||
|
product.description_short = removeStyles(product.description_short)
|
||||||
|
product.usage = removeStyles(product.usage)
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -89,7 +89,6 @@ export const useProductStore = defineStore('product', () => {
|
|||||||
available_now: stripHtml(productDescription.value?.available_now || ''),
|
available_now: stripHtml(productDescription.value?.available_now || ''),
|
||||||
available_later: stripHtml(productDescription.value?.available_later || ''),
|
available_later: stripHtml(productDescription.value?.available_later || ''),
|
||||||
usage: stripHtml(productDescription.value?.usage || ''),
|
usage: stripHtml(productDescription.value?.usage || ''),
|
||||||
// delivery_in_stock: stripHtml(productDescription.value?.delivery_in_stock || '')
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -109,120 +108,3 @@ export const useProductStore = defineStore('product', () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// import { defineStore } from 'pinia'
|
|
||||||
// import { ref } from 'vue'
|
|
||||||
// import { useFetchJson } from '@/composable/useFetchJson'
|
|
||||||
// import type { ProductDescription } from '@/types/product'
|
|
||||||
// import { useSettingsStore } from './settings'
|
|
||||||
|
|
||||||
// export interface Product {
|
|
||||||
// id: number
|
|
||||||
// image: string
|
|
||||||
// name: string
|
|
||||||
// code: string
|
|
||||||
// inStock: boolean
|
|
||||||
// priceFrom: number
|
|
||||||
// priceTo: number
|
|
||||||
// count: number
|
|
||||||
// description?: string
|
|
||||||
// howToUse?: string
|
|
||||||
// productDetails?: string
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface ProductResponse {
|
|
||||||
// items: Product[]
|
|
||||||
// items_count: number
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export const useProductStore = defineStore('product', () => {
|
|
||||||
// const productDescription = ref()
|
|
||||||
// const currentProduct = ref<Product | null>(null)
|
|
||||||
// const loading = ref(false)
|
|
||||||
// const error = ref<string | null>(null)
|
|
||||||
|
|
||||||
// async function getProductDescription(langId = 1, productID: number) {
|
|
||||||
// loading.value = true
|
|
||||||
// error.value = null
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// const response = await useFetchJson<ProductDescription>(
|
|
||||||
// `/api/v1/restricted/product-translation/get-product-description?productID=${productID}&productLangID=${langId}`
|
|
||||||
// )
|
|
||||||
// productDescription.value = response.items
|
|
||||||
// console.log(productDescription, 'dfsfsdf');
|
|
||||||
|
|
||||||
// } catch (e: unknown) {
|
|
||||||
// error.value = e instanceof Error ? e.message : 'Failed to load product description'
|
|
||||||
// } finally {
|
|
||||||
// loading.value = false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// function stripHtml(html: string) {
|
|
||||||
// const div = document.createElement('div')
|
|
||||||
// div.innerHTML = html
|
|
||||||
// return div.textContent || div.innerText || ''
|
|
||||||
// }
|
|
||||||
// async function saveProductDescription(productID?: number, langId?: number) {
|
|
||||||
// const id = productID || 1
|
|
||||||
// const lang = langId || 1
|
|
||||||
// try {
|
|
||||||
// const data = await useFetchJson(
|
|
||||||
// `/api/v1/restricted/product-translation/save-product-description?productID=${id}&productLangID=${lang}`,
|
|
||||||
// {
|
|
||||||
// method: 'POST',
|
|
||||||
// headers: {
|
|
||||||
// 'Content-Type': 'application/json'
|
|
||||||
// },
|
|
||||||
// body: JSON.stringify({
|
|
||||||
// name: stripHtml(productDescription.value?.name || ''),
|
|
||||||
// description: stripHtml(productDescription.value?.description || ''),
|
|
||||||
// description_short: stripHtml(productDescription.value?.description_short || ''),
|
|
||||||
// meta_title: stripHtml(productDescription.value?.meta_title || ''),
|
|
||||||
// meta_description: stripHtml(productDescription.value?.meta_description || ''),
|
|
||||||
// available_now: stripHtml(productDescription.value?.available_now || ''),
|
|
||||||
// available_later: stripHtml(productDescription.value?.available_later || ''),
|
|
||||||
// usage: stripHtml(productDescription.value?.usage || '')
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// return data
|
|
||||||
// } catch (e) {
|
|
||||||
// console.error(e)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const defaultLangId = ref(1)
|
|
||||||
// async function translateProductDescription(productID: number, fromLangId: number, defaultLangId: number, model: string = 'OpenAI') {
|
|
||||||
// loading.value = true
|
|
||||||
// error.value = null
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// const response = await useFetchJson<ProductDescription>(`/api/v1/restricted/product-translation/translate-product-description?productID=${productID}&productFromLangID=${fromLangId}&productToLangID=${defaultLangId}&model=${model}`)
|
|
||||||
// productDescription.value = response.items
|
|
||||||
// return response.items
|
|
||||||
// } catch (e: any) {
|
|
||||||
// error.value = e?.message || 'Failed to translate product description'
|
|
||||||
// console.error('Failed to translate product description:', e)
|
|
||||||
// } finally {
|
|
||||||
// loading.value = false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function clearCurrentProduct() {
|
|
||||||
// currentProduct.value = null
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// productDescription,
|
|
||||||
// currentProduct,
|
|
||||||
// loading,
|
|
||||||
// error,
|
|
||||||
// getProductDescription,
|
|
||||||
// clearCurrentProduct,
|
|
||||||
// saveProductDescription,
|
|
||||||
// translateProductDescription,
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
Reference in New Issue
Block a user