import getXPath from 'get-xpath'; import PropTypes from 'prop-types'; import { mixpanelEvents, mixpanelService } from '@ea11y-apps/global/services'; import { isValidCSS, rgbOrRgbaToHex, } from '@ea11y-apps/global/utils/color-contrast-helpers'; import { APIScanner } from '@ea11y-apps/scanner/api/APIScanner'; import { BACKGROUND_ELEMENT_CLASS, BLOCKS, } from '@ea11y-apps/scanner/constants'; import { useScannerWizardContext } from '@ea11y-apps/scanner/context/scanner-wizard-context'; import { scannerItem } from '@ea11y-apps/scanner/types/scanner-item'; import { buildPathToParent } from '@ea11y-apps/scanner/utils/build-path-to-parent'; import { focusOnElement, removeExistingFocus, } from '@ea11y-apps/scanner/utils/focus-on-element'; import { getElementByXPath } from '@ea11y-apps/scanner/utils/get-element-by-xpath'; import { getElementCSSSelector } from '@ea11y-apps/scanner/utils/get-element-css-selector'; import { getOuterHtmlByXpath } from '@ea11y-apps/scanner/utils/get-outer-html-by-xpath'; import { useEffect, useRef, useState } from '@wordpress/element'; export const useColorContrastForm = ({ item, current, setCurrent }) => { const { colorContrastData, resolved: resolvedBlock, setResolved, isResolved, isManage, setOpenedBlock, setColorContrastData, setIsManageChanged, updateRemediationList, currentScanId, } = useScannerWizardContext(); const type = isManage ? 'manage' : 'main'; const [loading, setLoading] = useState(false); const [firstOpen, setFirstOpen] = useState(true); const [parentChanged, setParentChanged] = useState(false); const isGlobal = colorContrastData?.[type]?.[current]?.isGlobal || item.global || false; const isGlobalRef = useRef(null); useEffect(() => { if (item?.node) { isGlobalRef.current = isGlobal; } }, [current]); const setIsGlobal = (value) => { updateData({ isGlobal: value, }); }; const updateData = (data) => { const updData = [...colorContrastData?.[type]]; updData[current] = { ...(colorContrastData?.[type]?.[current] || {}), ...data, }; setColorContrastData({ ...colorContrastData, [type]: updData, }); if (data.color || data.background) { const rule = buildCSSRule(updData[current]); updateCSS(rule); } }; const sendEvent = (method) => { mixpanelService.sendEvent(mixpanelEvents.backgroundAdaptorChanged, { method, }); }; useEffect(() => { if (!isManage && !firstOpen && isResolved(BLOCKS.colorContrast)) { removeExistingFocus(); setOpenedBlock(BLOCKS.main); } setFirstOpen(false); }, [isResolved(BLOCKS.colorContrast)]); const { color = item.messageArgs[3] || rgbOrRgbaToHex( window.getComputedStyle(item.node).getPropertyValue('color'), ), background = item.messageArgs[4], parents = item.isEdit ? buildPathToParent(item.node, item.parentNode) : [item.path.dom], resolved = false, backgroundChanged = item.isEdit, } = colorContrastData[type]?.[current] || {}; useEffect(() => { if (isManage && parentChanged) { const styles = document.getElementById('ea11y-remediation-styles'); if (styles) { styles.innerHTML = styles.innerHTML.replace(item.data.rule, ''); } } }, [parentChanged]); const changeColor = (updColor) => { updateData({ color: updColor, resolved: false }); }; const changeBackground = (updBackground) => { const element = getElementByXPath(parents.at(-1)); if (!element) { return; } updateData({ background: updBackground, resolved: false, backgroundChanged: true, }); }; const setParentLarger = () => { const element = getElementByXPath(parents.at(-1)); const parent = element?.parentElement; if (!element || !parent) { return; } try { const xpath = getXPath(parent, { ignoreId: true }); focusOnElement(parent, BACKGROUND_ELEMENT_CLASS); updateData({ parents: [...parents, xpath], resolved: false, }); setParentChanged(true); sendEvent('plus'); } catch (error) { console.warn('Failed to get XPath for parent element:', error); } }; const setParentSmaller = () => { const newParents = parents.slice(0, -1); const nextElement = getElementByXPath(newParents.at(-1)); if (parents.length <= 1 || !nextElement) { return; } if (newParents.length > 1) { focusOnElement(nextElement, BACKGROUND_ELEMENT_CLASS); } else { removeExistingFocus(BACKGROUND_ELEMENT_CLASS); } updateData({ parents: newParents, resolved: false }); setParentChanged(true); sendEvent('minus'); }; const isValidHexColor = (str) => /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(str.trim()); const buildCSSRule = (data) => { const currentParents = data.parents || parents; const currentParent = currentParents.length > 0 ? currentParents.at(-1) : item.path.dom; if ( (data.color && !isValidHexColor(data.color)) || (data.background && !isValidHexColor(data.background)) ) { throw new Error('Invalid hex color input detected'); } try { const bgElement = getElementByXPath(currentParent); const colorSelector = getElementCSSSelector(item.node); const bgSelector = getElementCSSSelector(bgElement); const colorRule = data.color ? `${colorSelector} {color: ${data.color} !important;}` : ''; const bgRule = data.background ? `${bgSelector} {background-color: ${data.background} !important;}` : ''; const css = `${colorRule}${bgRule}`; return isValidCSS(css) ? css : ''; } catch (e) { console.warn('Failed to convert XPath to CSS selector', e); return ''; } }; const updateCSS = (rule) => { let styles = document.getElementById('ea11y-remediation-styles-edit'); if (!styles) { styles = document.createElement('style'); styles.id = 'ea11y-remediation-styles-edit'; document.body.appendChild(styles); } styles.innerHTML = rule; }; const onUpdate = async () => { const rule = buildCSSRule(colorContrastData?.[type]?.[current]); const find = getOuterHtmlByXpath(item.path.dom); const parentXPath = parents.length > 0 ? parents.at(-1) : null; const parentFind = getOuterHtmlByXpath(parentXPath); try { setLoading(true); const remediation = colorContrastData?.[type]?.[current]?.remediation; const id = item.id || remediation.id; const data = item.data || JSON.parse(remediation.content); const updContent = JSON.stringify({ ...data, rule, find, parentFind, parentXPath, }); await APIScanner.updateRemediationContent({ url: window?.ea11yScannerData?.pageData?.url, id, content: updContent, global: isGlobal, }); setIsManageChanged(true); removeExistingFocus(); setParentChanged(false); updateCSS(rule); isGlobalRef.current = isGlobal; void updateRemediationList(); } catch (e) { console.error(e); } finally { setLoading(false); } }; const onSubmit = async () => { const parentXPath = parents.length > 0 ? parents.at(-1) : null; const parentFind = getOuterHtmlByXpath(parentXPath); setLoading(true); try { const rule = buildCSSRule(colorContrastData?.[type]?.[current]); const response = await APIScanner.submitRemediation({ url: window?.ea11yScannerData?.pageData?.url, remediation: { rule, category: item.reasonCategory.match(/\((AAA?|AA?|A)\)/)?.[1] || '', type: 'STYLES', xpath: item.path.dom, find: item.snippet, parentFind, parentXPath, }, global: isGlobal, rule: item.ruleId, group: BLOCKS.colorContrast, }); await APIScanner.resolveIssue(currentScanId); updateData({ remediation: response.remediation, resolved: true }); removeExistingFocus(); setCurrent(current + 1); setResolved(resolvedBlock + 1); setParentChanged(false); updateCSS(rule); isGlobalRef.current = isGlobal; void updateRemediationList(); } catch (error) { console.error('Failed to submit remediation:', error); } finally { setLoading(false); } }; const isDisabled = resolved && colorContrastData?.[type]?.[current]?.isGlobal === isGlobalRef.current; return { isGlobal, setIsGlobal, color, background, parents, isDisabled, resolved, backgroundChanged, parentChanged, loading, changeColor, changeBackground, setParentLarger, setParentSmaller, onSubmit, onUpdate, }; }; useColorContrastForm.propTypes = { item: scannerItem.isRequired, current: PropTypes.number.isRequired, setCurrent: PropTypes.func.isRequired, }; ketritsg – EM SANG Boutique – Thương hiệu thời trang nữ phong cách đa dạng với hàng nghìn mẫu thiết kế https://emsang.vn Thương hiệu thời trang nữ phong cách đa dạng với hàng nghìn mẫu thiết kế Thu, 11 Jul 2024 02:30:43 +0000 vi hourly 1 https://wordpress.org/?v=7.0 https://emsang.vn/wp-content/uploads/2024/07/cropped-favicon-32x32.png ketritsg – EM SANG Boutique – Thương hiệu thời trang nữ phong cách đa dạng với hàng nghìn mẫu thiết kế https://emsang.vn 32 32 Mừng Khai trương Store EM SANG 422 Hai Bà Trưng, Quận 1 https://emsang.vn/mung-khai-truong-store-em-sang-422-hai-ba-trung-quan-1/ https://emsang.vn/mung-khai-truong-store-em-sang-422-hai-ba-trung-quan-1/#respond Thu, 11 Jul 2024 02:30:43 +0000 https://emsang.ecosu.com.vn/?p=975
𝐌𝐮̛̀𝐧𝐠 𝐊𝐡𝐚𝐢 𝐓𝐫𝐮̛𝐨̛𝐧𝐠 𝐒𝐭𝐨𝐫𝐞 𝐄𝐌 𝐒𝐀𝐍𝐆 𝟒𝟐𝟐 𝐇𝐚𝐢 𝐁𝐚̀ 𝐓𝐫𝐮̛𝐧𝐠, 𝐐𝐮𝐚̣̂𝐧 𝟏🎉
🥰Hôm nay EM SANG đã chính thức mở cửa tại 422 Hai Bà Trưng, Tân Định, Quận 1!
Buổi lễ Grand Opening sáng nay diễn ra rất thành công và tốt đẹp. Chúng mình rất vui mừng khi đón tiếp nhiều khách hàng và bạn bè đến tham dự và ủng hộ để cùng tạo nên khoảnh khắc đáng nhớ này.
Cảm ơn tất cả mọi người đã đến tham dự cùng EM SANG 422 Hai Bà Trưng. Hãy tiếp tục theo dõi và đồng hành cùng EM SANG để cập nhật những xu hướng thời trang mới nhất nhé!
💥💥S.I.Ê.U H.O.T: Nhân dịp khai trương, EM SANG dành tặng các bạn:
◾VOUCHER trị giá lên đến 200K khi mua hàng với hóa đơn từ 500K.
◾Hàng ngàn quà tặng hấp dẫn với hóa đơn từ 1500K.
Đừng bỏ lỡ những ưu đãi siêu hot mà EM SANG dành cho các bạn nhé!
📌Đặc biệt: EM SANG sắp ra mắt cửa hàng mới trong tháng 7 tại 283-285 Quang Trung, P.10, Gò Vấp.
Đừng bỏ lỡ cơ hội trải nghiệm mua sắm tuyệt vời tại EM SANG – 422 Hai Bà Trưng, Tân Định, Quận 1 nhé!
]]>
https://emsang.vn/mung-khai-truong-store-em-sang-422-hai-ba-trung-quan-1/feed/ 0
𝐈𝐭𝐞𝐦 𝐛𝐞𝐬𝐭- 𝐬𝐞𝐥𝐥𝐞𝐫 𝐛𝐲 𝐄𝐌 𝐒𝐀𝐍𝐆 https://emsang.vn/%f0%9d%90%88%f0%9d%90%ad%f0%9d%90%9e%f0%9d%90%a6-%f0%9d%90%9b%f0%9d%90%9e%f0%9d%90%ac%f0%9d%90%ad-%f0%9d%90%ac%f0%9d%90%9e%f0%9d%90%a5%f0%9d%90%a5%f0%9d%90%9e%f0%9d%90%ab-%f0%9d%90%9b%f0%9d%90%b2/ https://emsang.vn/%f0%9d%90%88%f0%9d%90%ad%f0%9d%90%9e%f0%9d%90%a6-%f0%9d%90%9b%f0%9d%90%9e%f0%9d%90%ac%f0%9d%90%ad-%f0%9d%90%ac%f0%9d%90%9e%f0%9d%90%a5%f0%9d%90%a5%f0%9d%90%9e%f0%9d%90%ab-%f0%9d%90%9b%f0%9d%90%b2/#respond Thu, 11 Jul 2024 02:29:11 +0000 https://emsang.ecosu.com.vn/?p=972 𝐈𝐭𝐞𝐦 𝐛𝐞𝐬𝐭- 𝐬𝐞𝐥𝐥𝐞𝐫 𝐛𝐲 𝐄𝐌 𝐒𝐀𝐍𝐆
🥰Các nàng đừng bỏ lỡ áo ba lỗ cổ sâu được thiết kế dành riêng cho mùa hè của EM SANG với chất liệu siêu mát, thấm hút mồ hôi tốt. Kết hợp cùng quần jean suông, chất co giãn nhẹ. Diện em set này vừa thanh lịch mà vẫn cực kì trendy luôn ạ.
]]>
https://emsang.vn/%f0%9d%90%88%f0%9d%90%ad%f0%9d%90%9e%f0%9d%90%a6-%f0%9d%90%9b%f0%9d%90%9e%f0%9d%90%ac%f0%9d%90%ad-%f0%9d%90%ac%f0%9d%90%9e%f0%9d%90%a5%f0%9d%90%a5%f0%9d%90%9e%f0%9d%90%ab-%f0%9d%90%9b%f0%9d%90%b2/feed/ 0
Sofie Top và Forever Skirt – sự kết hợp hoàn hảo giữa sơ mi cao cấp và chân váy lụa sang trọng https://emsang.vn/sofie-top-va-forever-skirt-su-ket-hop-hoan-hao-giua-so-mi-cao-cap-va-chan-vay-lua-sang-trong/ https://emsang.vn/sofie-top-va-forever-skirt-su-ket-hop-hoan-hao-giua-so-mi-cao-cap-va-chan-vay-lua-sang-trong/#respond Thu, 11 Jul 2024 02:28:19 +0000 https://emsang.ecosu.com.vn/?p=969
𝐒𝐨𝐟𝐢𝐞 𝐓𝐨𝐩 𝐌𝐢𝐱 𝐅𝐨𝐫𝐞𝐯𝐞𝐫 𝐒𝐤𝐢𝐫𝐭 – 𝐓𝐡𝐚𝐧𝐡 𝐋𝐢̣𝐜𝐡 𝐯𝐚̀ Đ𝐚̆̉𝐧𝐠 𝐂𝐚̂́𝐩
✨ Sofie Top và Forever Skirt – sự kết hợp hoàn hảo giữa sơ mi cao cấp và chân váy lụa sang trọng.
✨Mềm mại, tinh tế và đầy quyến rũ, set đồ này lý tưởng cho mọi hoàn cảnh, từ công sở đến những buổi tiệc quan trọng.
]]>
https://emsang.vn/sofie-top-va-forever-skirt-su-ket-hop-hoan-hao-giua-so-mi-cao-cap-va-chan-vay-lua-sang-trong/feed/ 0
Golden Harvest nhà EMSANG https://emsang.vn/golden-harvest-nha-emsang/ https://emsang.vn/golden-harvest-nha-emsang/#respond Thu, 11 Jul 2024 02:19:43 +0000 https://emsang.ecosu.com.vn/?p=960
𝐆𝐨𝐥𝐝𝐞𝐧 𝐇𝐚𝐫𝐯𝐞𝐬𝐭
💃Phối đồ mùa hè đơn giản, thoải mái, điệu đà dành cho các nàng nhà EM SANG đâyyy.
💃Croptop đen x áo sơ mi khoác ngoài mix cùng chân váy midi mang lại phong cách hiện đại, nổi bật và đầy cuốn hút.
]]>
https://emsang.vn/golden-harvest-nha-emsang/feed/ 0
EM SANG style trong phiên bản Cobalt Blue https://emsang.vn/em-sang-style-trong-phien-ban-cobalt-blue/ https://emsang.vn/em-sang-style-trong-phien-ban-cobalt-blue/#respond Thu, 11 Jul 2024 02:18:51 +0000 https://emsang.ecosu.com.vn/?p=957 𝐂𝐨𝐛𝐚𝐥𝐭 𝐁𝐥𝐮𝐞
💙Sang trọng – Quyến rũ là hai từ để mô tả quý cô EM SANG style trong phiên bản Cobalt Blue.
💙Áo khoác xanh cobalt khi kết hợp cùng quần ống rộng và áo croptop giúp nàng toát lên sự sang trọng và trẻ trung, dạo phố hay cà hê đề ô cơ.
]]>
https://emsang.vn/em-sang-style-trong-phien-ban-cobalt-blue/feed/ 0