1/1
${data.index + 1}/${data.total}
/** @private {string} */
class SpzCustomAnchorScroll extends SPZ.BaseElement {
static deferredMount() {
return false;
}
constructor(element) {
super(element);
/** @private {Element} */
this.scrollableContainer_ = null;
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.LOGIC;
}
buildCallback() {
this.viewport_ = this.getViewport();
this.initActions_();
}
setTarget(containerId, targetId) {
this.containerId = '#' + containerId;
this.targetId = '#' + targetId;
}
scrollToTarget() {
const container = document.querySelector(this.containerId);
const target = container.querySelector(this.targetId);
const {scrollTop} = container;
const eleOffsetTop = this.getOffsetTop_(target, container);
this.viewport_
.interpolateScrollIntoView_(
container,
scrollTop,
scrollTop + eleOffsetTop
);
}
initActions_() {
this.registerAction(
'scrollToTarget',
(invocation) => this.scrollToTarget(invocation?.caller)
);
this.registerAction(
'setTarget',
(invocation) => this.setTarget(invocation?.args?.containerId, invocation?.args?.targetId)
);
}
/**
* @param {Element} element
* @param {Element} container
* @return {number}
* @private
*/
getOffsetTop_(element, container) {
if (!element./*OK*/ getClientRects().length) {
return 0;
}
const rect = element./*OK*/ getBoundingClientRect();
if (rect.width || rect.height) {
return rect.top - container./*OK*/ getBoundingClientRect().top;
}
return rect.top;
}
}
SPZ.defineElement('spz-custom-anchor-scroll', SpzCustomAnchorScroll);
const STRENGTHEN_TRUST_URL = "/api/strengthen_trust/settings";
class SpzCustomStrengthenTrust extends SPZ.BaseElement {
constructor(element) {
super(element);
this.renderElement_ = null;
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
buildCallback() {
this.xhr_ = SPZServices.xhrFor(this.win);
const renderId = this.element.getAttribute('render-id');
SPZCore.Dom.waitForChild(
document.body,
() => !!document.getElementById(renderId),
() => {
this.renderElement_ = SPZCore.Dom.scopedQuerySelector(
document.body,
`#${renderId}`
);
if (this.renderElement_) {
this.render_();
}
this.registerAction('track', (invocation) => {
this.track_(invocation.args);
});
}
);
}
render_() {
this.fetchData_().then((data) => {
if (!data) {
return;
}
SPZ.whenApiDefined(this.renderElement_).then((apis) => {
apis?.render(data);
document.querySelector('#strengthen-trust-render-1711101560621').addEventListener('click',(event)=>{
if(event.target.nodeName == 'A'){
this.track_({type: 'trust_content_click'});
}
})
});
});
}
track_(data = {}) {
const track = window.sa && window.sa.track;
if (!track) {
return;
}
track('trust_enhancement_event', data);
}
parseJSON_(string) {
let result = {};
try {
result = JSON.parse(string);
} catch (e) {}
return result;
}
fetchData_() {
return this.xhr_
.fetchJson(STRENGTHEN_TRUST_URL)
.then((responseData) => {
if (!responseData || !responseData.data) {
return null;
}
const data = responseData.data;
const moduleSettings = (data.module_settings || []).reduce((result, moduleSetting) => {
return result.concat(Object.assign(moduleSetting, {
logos: (moduleSetting.logos || []).map((item) => {
return moduleSetting.logos_type == 'custom' ? this.parseJSON_(item) : item;
})
}));
}, []);
return Object.assign(data, {
module_settings: moduleSettings,
isEditor: window.self !== window.top,
});
});
}
}
SPZ.defineElement('spz-custom-strengthen-trust', SpzCustomStrengthenTrust);
${data.module_title}
To display this card to customers, you need to go to "Booster & Store Conversion" to turn on the trust enhancement feature.
${item.content.replaceAll("{store_name}","Handcrafts Store®")}
To display this card to customers, you need to go to "Booster & Store Conversion" to turn on the trust enhancement feature.
Features: DIY painting: unique design, the use of resin as varnish and the unique luster of resin sequins is dazzling. Shining: The most popular DIY decoration. Specification: Material: keychain + resin diamond Diamond type: special-shaped diamond DIY diamond painting production steps: 1. Open the box and check if the diamond painting is complete. 2. Check the resin diamond color and arrange the codes in order. 3. Uncover the tape picture above, you will see a lot of symbols corresponding to the color coding. 4. According to the corresponding color coded clip, inlay diamonds on the corresponding resin. 5. Recommend a resin and diamond suit, it will be completed faster. 6. In order to draw a perfect diamond painting, put the drawing in one place, and don't leave any diamonds behind every symbol. 7. To cut out good graphics, please arrange and install them on the upper material plane. 8. The patchwork needs to be flat, neat and free of cracks. 9. After finishing, the remaining glue seam conforms to the diamond symbol. 10. To complete a good diamond painting, place it in the appropriate frame of your choice. (This product does not provide a framework.) Note: This is a DIY diamond painting, not a finished picture, you need to complete it yourself. All products are measured manually, so please allow a deviation of 1-2cm. Due to differences in lighting and screens, the color of the product may be slightly different from the picture. Please understand.
USA and Canada: 7 - 14 Business days
Oceania: 7 - 21 Business days
Europe: 5 - 10 Business days
Latin America: 10 - 25 Business days
Other countries: 14 - 30 Business days
Orders can be cancelled or modified within 2 hours after being placed
Tracking Number: When available, we will send you the tracking number with the confirmation email so that you can track the package online.
International orders: It may take additional days if orders have to go through customs.
Free Shipping for all U.S. orders over $49
We need to take 1-3 days to process the order after you done the payment. We do not ship on weekends.
Safe payments via Paypal®
100% Moneyback Guarantee.
24/7 assistance admin@oadiy.com
We have 24/7/365 Email Support. Please contact us if need assistance.
Worldwide tracked shipping.
Tracking numbers will be emailed to you once the item is shipped!
No hidden fees!
If you don’t have a positive experience for ANY reason, we will do WHATEVER it takes to make sure you are 100% satisfied with your purchase.
STEP 1
Begin with a clean slate by removing the protective layer
STEP 2
Let the intuitive design guide you - match symbols with ease
STEP 3
Prepare your pen with just a touch of wax
STEP 4
Gently pick and place each diamond, like stars in the sky
STEP 5
Witness a tapestry of color blossom before you
STEP 6
Revel in the completion of your very own masterpiece coasters
FAQs
Frequently asked question
Email us at huayutrading2022@hotmail.com if you cannot find your answers.
How many pieces do I get?
We sell in both individual piece and a set of coasters. Please kindly select accordingly.
How do the coasters handle moisture?
We recommend to coat the coasters with diamond painting sealant to waterproof it.
Do glasses slip on them when condensatation starts running down the outside of a cold drink?
We tested it ourselves and haven't met with any issues. The same goes for our customers.
What is the coaster made of?
Our coasters are made of premium wood that is sure to last for a long time.
Here are what our customers say.
Newest
Most liked
Highest ratings
Lowest ratings
Wow you reached the bottom
Most liked
Highest ratings
Lowest ratings
×
${function(){
const limit = typeof data === 'number' ? data : 0;
return `
Pictures/Videos (${limit || 0}/5 )
` }()}
${(function(){
const closeIcon =
'
';
if (item.type === 'image') {
return `
${closeIcon}
`
}
return `
${closeIcon}
`
})()}
Submit Comments Anonymously
class SpzCustomFileUpload extends SPZ.BaseElement {
constructor(element) {
super(element);
this.uploadCount_ = 0;
this.fileList_ = [];
}
buildCallback() {
this.action = SPZServices.actionServiceForDoc(this.element);
this.registerAction('upload', (data) => {
this.handleFileUpload_(data.event?.detail?.data || []);
});
this.registerAction('delete', (data) => {
this.handleFileDelete_(data?.args?.data);
});
this.registerAction('preview', (data) => {
this.handleFilePreview_(data?.args?.data);
});
this.registerAction('limit', (data) => {
this.handleFileLimit_();
});
this.registerAction('sizeLimit', (data) => {
this.handleFileSizeLimit_();
});
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.LOGIC;
}
setData_(count, file) {
this.uploadCount_ = count;
this.fileList_ = file;
}
handleFileUpload_(data) {
data.forEach(i => {
if(this.fileList_.some(j => j.url === i.url)) return;
this.fileList_.push(i);
})
this.uploadCount_++;
sessionStorage.setItem('fileList', JSON.stringify(this.fileList_));
this.triggerEvent_("handleFileUpload", { count: this.uploadCount_, files: this.fileList_});
if(this.fileList_.length >= 5){
document.querySelector('#review_upload').style.display = 'none';
}
if(this.fileList_.length > 0){
document.querySelector('.apps-reviews-write-anonymous-box').style.marginTop = '8px';
}
}
handleFileDelete_(index) {
this.fileList_.splice(index, 1);
this.uploadCount_--;
sessionStorage.setItem('fileList', JSON.stringify(this.fileList_));
this.triggerEvent_("handleFileDelete", { count: this.uploadCount_, files: this.fileList_});
document.querySelector('#review_upload').style.display = 'block';
if(this.fileList_?.length === 0){
document.querySelector('.apps-reviews-write-anonymous-box').style.marginTop = '132px';
}
}
handleFilePreview_(index) {
const finalPreviewData = this.fileList_[index];
const filePreviewModal = document.getElementById('filePreviewModal');
const fullScreenVideo = document.getElementById('fullScreenVideo');
const fullScreenImage = document.getElementById('fullScreenImage');
const previewModalClose = document.getElementById('previewModalClose');
const previewLoading = document.getElementById('previewLoading');
filePreviewModal.style.display = 'block';
previewLoading.style.display = 'flex';
if(finalPreviewData?.type === 'video'){
const media = this.mediaParse_(this.fileList_[index]?.url);
fullScreenVideo.addEventListener('canplaythrough', function() {
previewLoading.style.display = 'none';
});
fullScreenImage.src = '';
fullScreenImage.style.display = 'none';
fullScreenVideo.style.display = 'block';
fullScreenVideo.src = media.mp4 || '';
} else {
fullScreenImage.onload = function() {
previewLoading.style.display = 'none';
};
fullScreenVideo.src = '';
fullScreenVideo.style.display = 'none';
fullScreenImage.style.display = 'block';
fullScreenImage.src = finalPreviewData.url;
}
previewModalClose.addEventListener('click', function() {
filePreviewModal.style.display = 'none';
});
}
handleFileLimit_() {
alert(window.AppReviewsLocale.comment_file_limit || 'please do not upload files more than 5');
this.triggerEvent_("handleFileLimit");
}
handleFileSizeLimit_() {
alert(window.AppReviewsLocale.comment_file_size_limit || 'File size does not exceed 10M');
}
clear(){
this.fileList_ = [];
this.uploadCount_ = 0;
sessionStorage.setItem('fileList', JSON.stringify(this.fileList_));
this.triggerEvent_("handleClear", { count: this.uploadCount_, files: this.fileList_});
document.querySelector('#review_upload').style.display = 'block';
}
mediaParse_(url) {
var result = {};
try {
url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
try {
result[key] = decodeURIComponent(value);
} catch (e) {
result[key] = value;
}
});
result.preview_image = url.split('?')[0];
} catch (e) {};
return result;
}
triggerEvent_(name, data) {
const event = SPZUtils.Event.create(this.win, name, data);
this.action.trigger(this.element, name, event);
}
}
SPZ.defineElement('spz-custom-file-upload', SpzCustomFileUpload);
The review would not show in product details on storefront since it does not support to.
Social Welfare
We created a fundraising plan that combines both! With every order placed at Handcrafts Store®, we make a donation to a charitable organization. Whether it's the Global Fund, your local Red Cross, or any other charity, Handcrafts Store® is happy to support your cause!
Your shopping bag is empty
Continue shopping
*${item.quantity}
${item.item_text}
${discount_item.title}
(- )
${(function(){
var total_price = data.total_price;
var postageFreeAmount = 39;
var freeAmount = postageFreeAmount - total_price;
var isFreeShipping = freeAmount <= 0;
var rate = Math.min(total_price / postageFreeAmount * 100, 100).toFixed(2);
const textArray = ("Spend {{ amount }} more and get free shipping!").split(/\{\{\s*amount\s*\}\}/);
const textArrayHtml = textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `${text} `;
}).join('');
return `
${textArrayHtml}
You've got free shipping
`
})()}
${function() {
const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${function() {
const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${discount_application.title}:
-
${data.invalid_msg}
Check out
Taxes and shipping calculated at checkout
${(function(){
var total_price = data.total_price;
var postageFreeAmount = 39;
var freeAmount = postageFreeAmount - total_price;
var isFreeShipping = freeAmount <= 0;
var rate = Math.min(total_price / postageFreeAmount * 100, 100).toFixed(2);
const textArray = ("Spend {{ amount }} more and get free shipping!").split(/\{\{\s*amount\s*\}\}/);
const textArrayHtml = textArray.map((text, index) => {
if (index == 0) {
return `
${text} `;
}
return `
${text} `;
}).join('');
return `
${textArrayHtml}
You've got free shipping
`
})()}
${data.invalid_msg}
${function() {
const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${function() {
const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${function() {
const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/);
if (textArray.length > 0 && textArray.length < 2) {
textArray.push('');
}
return textArray.map((text, index) => {
if (index == 0) {
return `${text} `;
}
return `
${text}
`;
}).join('');
}()}
${discount_application.title}:
-
Check out
${data.invalid_msg}
Check out
Taxes and shipping calculated at checkout
Subtotal:
${discount_application.title}:
-
Check out
Taxes and shipping calculated at checkout
const summaryStickyRender = document.querySelector('#cart-drawer-summary-sticky-render');
if (summaryStickyRender) {
document.body.style.setProperty('--cart-drawer-summary-sticky-height', summaryStickyRender.clientHeight + 'px');
}
${function(){
const productData = data.product;
let product_change_event = '',
mouse_over_event = ' ';
mouse_out_event = '';
const product_options = productData.options.filter(Boolean) || [];
for (let opt of product_options) {
product_change_event = product_change_event + `quick-shop-selected-variant-${opt.name}.rerender(data=event.selectedValues.${opt.name});`;
mouse_out_event = mouse_out_event + `quick-shop-selected-variant-${opt.name}.rerender(data=event.selectData.${opt.name});`;
mouse_over_event = mouse_over_event + `@${opt.name}Mouseover="quick-shop-selected-variant-${opt.name}.rerender(data=event);"`;
}
const selectedVariant = productData.variants.find(v => v.available) || productData.variants[0];
const statusLan = ((selectedVariant && !selectedVariant.available) || (!selectedVariant && !productData.available)) ?
"Sold out" :
"Add to cart";
return `
`
}()}
${function(){
const currentSelectVariant = data.variant;
const defaultVariant = (data.product && data.product.variants && data.product.variants[0]);
const variantData = currentSelectVariant || defaultVariant || data;
const retail_price = variantData.retail_price || 0;
return `
`
}()}
${function(){
const wholesale_enabled = false;
const qty = data.quantity || 1;
const currentSelectVariant = data.variant;
const defaultVariant = (data.product && data.product.variants && data.product.variants[0]);
const productVariant = {"id":"9d250dc9-502f-4803-99b2-c90fb3c1e6a1","product_id":"210d7402-f45e-4b63-a9ac-6644f85dc52c","title":"","weight_unit":"kg","inventory_quantity":997,"sku":"B052","barcode":"","position":1,"option1":"","option2":"","option3":"","note":"","image":null,"wholesale_price":[{"price":13.99,"min_quantity":1}],"weight":"0.23","compare_at_price":"64.99","price":"13.99","retail_price":"64.99","available":true,"url":"\/products\/6pcs-diy-diamond-painting-keychain-roosters-single-side?variant=9d250dc9-502f-4803-99b2-c90fb3c1e6a1","available_quantity":997,"options":[],"off_ratio":78,"flashsale_info":[],"sales":3};
const variantData = currentSelectVariant || defaultVariant || productVariant;
const wholesale_price = variantData.wholesale_price || [];
if(wholesale_enabled && wholesale_price.length > 0) {
let wholesaleIndex = wholesale_price.findIndex(item => {
return item.min_quantity > qty;
});
if(wholesaleIndex < 0){
wholesaleIndex = wholesale_price.length - 1;
}else if(wholesaleIndex > 0){
wholesaleIndex = wholesaleIndex - 1;
}
const wholesalePrice = wholesale_price[wholesaleIndex] || '';
return `
`
}else {
const price = variantData && variantData.price;
return price != undefined ? `
` : ' ';
}
}()}
${function() {
let variantImageShowed = false;
const currentProduct = data.product;
return (currentProduct.options || []).map((option, index) => {
const optionName = option.name || '';
const position = `option${index + 1}`;
let isThumbImage = false;
if (currentProduct.need_variant_image && !variantImageShowed) {
const variantNames = ["color"] || [];
for (let i = 0, len = variantNames.length; i < len; i++) {
const name = variantNames[i].toLowerCase();
if (name === optionName.toLowerCase()) {
isThumbImage = true;
variantImageShowed = true;
}
}
}
const variantType = "button";
const thumbStyle = "image_with_text";
return `
${optionName}:
${option.values.map((value, idx) => {
const selected = data.selectedValues[optionName] == value ? 'checked' : '';
let thumbImage = null;
if (isThumbImage) {
const variants = currentProduct.variants;
for (let i = 0, len = variants.length; i < len; i++) {
const variant = variants[i];
if (variant[position] == value && thumbImage == null) {
thumbImage = variant.image;
break;
}
}
}
return `
${value}
`
}).join('')}
${optionName}
${option.values.map(value => {
const selected = data.selectedValues[optionName] == value ? 'selected' : '';
return `${value} `
}).join('')}
`
}).join('');
}()}
${data.originData && data.originData.value || data.value}
const TAG = 'spz-custom-painter-button-animation';
const MAX_ITERATION_COUNT = 99999999;
const SITE = (window.C_SETTINGS && window.C_SETTINGS.routes && window.C_SETTINGS.routes.root) || '';
const ADD_TO_CART_ANIMATION_SETTING =
`${SITE}/api/marketing_atmosphere_app/add_to_cart_btn_animation/setting`;
class SpzCustomPainterButtonAnimation extends SPZ.BaseElement {
/**@override */
static deferredMount() {
return false;
}
/** @param {!SpzElement} element */
constructor(element) {
super(element);
/** @private {!../../src/service/xhr-impl.Xhr} */
this.xhr_ = SPZServices.xhrFor(this.win);
/** @private {Object} */
this.data_ = null;
/** @private {Element} */
this.addToCartButton_ = null;
/** @private {boolean} */
this.productAvailable_ = true;
/** @private {number} */
this.timerId_ = null;
/** @private {number} */
this.animationExecutionCount_ = 0;
/** @private {boolean} */
this.selectedVariantAvailable_ = true;
/** @private {number} */
this.delay_ = 5000;
/** @private {number} */
this.iterationCount_ = 5;
/** @private {string} */
this.animationClass_ = '';
}
/** @override */
isLayoutSupported(layout) {
return layout == SPZCore.Layout.LOGIC;
}
/** @override */
buildCallback() {
this.productAvailable_ = this.element.hasAttribute('product-available');
this.selectedVariantAvailable_ = this.element.hasAttribute('selected-variant-available');
}
/** @override */
mountCallback() {
this.render_();
}
/** @private */
render_() {
if (!this.productAvailable_) {
return;
}
this.fetch_().then((data) => {
if (!data) {
return;
}
this.data_ = data;
this.animationClass_ = `painter-${data.animation_name}-animation`;
this.iterationCount_ =
data.animation_iteration_count === 'infinite'
? MAX_ITERATION_COUNT
: data.animation_iteration_count;
const animationDuration = 1;
const animationDelay = data.animation_delay || 5;
this.delay_ = (animationDuration + animationDelay) * 1000;
this.handleButtonEffect_();
});
}
/**
* @param {JsonObject} data
* @return {(null|Object)}
* @private
*/
parseJson_(data) {
try {
return JSON.parse(data);
} catch (e) {
return null;
}
}
/**
* @return {Promise}
* @private
*/
fetch_() {
return this.xhr_.fetchJson(ADD_TO_CART_ANIMATION_SETTING).then((data) => {
if (!data || !data.enabled) {
return null;
}
return this.parseJson_(data.detail);
});
}
/** @private */
getAddToCartButton_() {
this.addToCartButton_ = SPZCore.Dom.scopedQuerySelector(
document.body,
'[data-section-type="product"] [role="addToCart"], [data-section-type="product_detail"] [role="addToCart"], [data-section-type="product_detail"] [data-click="addToCart"], [data-section-type="product"] [data-click="addToCart"]'
);
}
/** @private */
restartAnimation_() {
this.addToCartButton_.classList.remove(this.animationClass_);
this.addToCartButton_./* OK */ offsetWidth;
this.addToCartButton_.classList.add(this.animationClass_);
this.animationExecutionCount_++;
}
/** @private */
clearTimer_() {
this.win.clearInterval(this.timerId_);
this.timerId_ = null;
}
/** @private */
setupTimer_() {
this.timerId_ = this.win.setInterval(() => {
this.restartAnimation_();
if (this.animationExecutionCount_ >= this.iterationCount_) {
this.removeAnimationClass_();
this.clearTimer_();
}
}, this.delay_);
}
/** @private */
restartTimer_() {
if (this.animationExecutionCount_ >= this.iterationCount_) {
this.removeAnimationClass_();
return;
}
this.setupTimer_();
}
/** @private */
listenVariantChange_() {
SPZUtils.Event.listen(self.document, 'dj.variantChange', (e) => {
const selectedVariant = e.detail && e.detail.selected;
if (!selectedVariant) {
return;
}
const {available} = selectedVariant;
if (this.selectedVariantAvailable_ !== available) {
this.selectedVariantAvailable_ = available;
this.clearTimer_();
if (available) {
this.restartTimer_();
}
}
});
}
/** @private */
removeAnimationClass_() {
this.win.setTimeout(() => {
this.addToCartButton_.classList.remove(this.animationClass_);
}, 1000);
}
/** @private */
handleButtonEffect_() {
this.getAddToCartButton_();
if (!this.addToCartButton_) {
return;
}
if (this.selectedVariantAvailable_) {
++this.animationExecutionCount_;
this.addToCartButton_.classList.add(this.animationClass_);
if (this.iterationCount_ === 1) {
this.removeAnimationClass_();
return;
}
this.setupTimer_();
}
this.listenVariantChange_();
}
}
SPZ.defineElement(TAG, SpzCustomPainterButtonAnimation);