Version 1
@@ -0,0 +1,43 @@
|
||||
FAVICON PACKAGE FOR: Royal-Pop-Accesory
|
||||
Generated by ConvertICO.com - Favicon Package Generator
|
||||
============================================================
|
||||
|
||||
CONTENTS:
|
||||
---------
|
||||
- favicon.ico Multi-size ICO (16x16, 32x32, 48x48)
|
||||
- favicon-16x16.png Browser tab favicon
|
||||
- favicon-32x32.png High-DPI browser favicon
|
||||
- favicon-48x48.png Windows site icon
|
||||
- apple-touch-icon.png iOS home screen (180x180)
|
||||
- apple-touch-icon-152x152.png iPad
|
||||
- apple-touch-icon-120x120.png iPhone
|
||||
- apple-touch-icon-76x76.png iPad mini
|
||||
- android-chrome-192x192.png Android home screen
|
||||
- android-chrome-512x512.png Android splash screen
|
||||
- mstile-150x150.png Windows tile
|
||||
- mstile-310x310.png Windows large tile
|
||||
- site.webmanifest Web app manifest (Android PWA)
|
||||
- browserconfig.xml Microsoft browser config
|
||||
|
||||
INSTALLATION:
|
||||
-------------
|
||||
1. Upload all files to your website's /favicon directory.
|
||||
|
||||
2. Add this code to your HTML <head> section:
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/favicon/site.webmanifest">
|
||||
<meta name="msapplication-TileColor" content="#e9e9e9">
|
||||
<meta name="theme-color" content="#e9e9e9">
|
||||
|
||||
NOTES:
|
||||
------
|
||||
- This project serves all favicon assets from /favicon for cleaner public asset organization
|
||||
- Modern browsers prefer PNG favicons but ICO provides legacy support
|
||||
- site.webmanifest enables 'Add to Home Screen' on Android
|
||||
- browserconfig.xml enables Windows Start menu tiles
|
||||
|
||||
Need more sizes or formats? Visit https://convertico.com for more tools!
|
||||
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/favicon/mstile-150x150.png"/>
|
||||
<square310x310logo src="/favicon/mstile-310x310.png"/>
|
||||
<TileColor>#e9e9e9</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
After Width: | Height: | Size: 707 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Royal-Pop-Accesory",
|
||||
"short_name": "Royal-Pop-Accesory",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/favicon/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/favicon/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#e9e9e9",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 2.4 MiB |
|
After Width: | Height: | Size: 3.3 MiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 3.8 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 201 KiB |
|
After Width: | Height: | Size: 296 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 108 KiB |
@@ -0,0 +1,4 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: https://royal-pop-accessory.com/sitemap.xml
|
||||
@@ -0,0 +1,190 @@
|
||||
(function () {
|
||||
const ROYAL_POP_CART_KEY = "royal-pop-cart";
|
||||
const ROYAL_POP_BUILDER_KEY = "royal-pop-builder-selection";
|
||||
const ROYAL_POP_CART_LIMIT = Number.POSITIVE_INFINITY;
|
||||
|
||||
const isBrowser = () => typeof window !== "undefined" && typeof window.localStorage !== "undefined";
|
||||
|
||||
const readJson = (key, fallback) => {
|
||||
if (!isBrowser()) return fallback;
|
||||
|
||||
try {
|
||||
const raw = window.localStorage.getItem(key);
|
||||
if (!raw) return fallback;
|
||||
return JSON.parse(raw);
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
|
||||
const writeJson = (key, value) => {
|
||||
if (!isBrowser()) return;
|
||||
|
||||
try {
|
||||
window.localStorage.setItem(key, JSON.stringify(value));
|
||||
} catch {
|
||||
// Ignore storage write failures.
|
||||
}
|
||||
};
|
||||
|
||||
const createItemId = () => {
|
||||
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
return `rp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
};
|
||||
|
||||
const normalizeSelection = (selection) => ({
|
||||
style: selection && selection.style === "A" ? "A" : "B",
|
||||
colorwayId: (selection && selection.colorwayId) || "sorbet-pop-multi-color",
|
||||
finishId: (selection && selection.finishId) || "silver",
|
||||
quantity: Math.max(1, Math.round(Number(selection && selection.quantity) || 1)),
|
||||
});
|
||||
|
||||
const loadBuilderSelection = () => {
|
||||
const selection = readJson(ROYAL_POP_BUILDER_KEY, null);
|
||||
if (!selection) return null;
|
||||
return normalizeSelection(selection);
|
||||
};
|
||||
|
||||
const saveBuilderSelection = (selection) => {
|
||||
writeJson(ROYAL_POP_BUILDER_KEY, normalizeSelection(selection));
|
||||
};
|
||||
|
||||
const loadCart = () => {
|
||||
const items = readJson(ROYAL_POP_CART_KEY, []);
|
||||
|
||||
return items
|
||||
.filter((item) => item && item.colorwayId && item.finishId)
|
||||
.map((item) => ({
|
||||
id: item.id || createItemId(),
|
||||
style: item.style === "A" ? "A" : "B",
|
||||
colorwayId: String(item.colorwayId),
|
||||
finishId: String(item.finishId),
|
||||
quantity: Math.max(1, Math.round(Number(item.quantity) || 1)),
|
||||
}))
|
||||
;
|
||||
};
|
||||
|
||||
const saveCart = (items) => {
|
||||
writeJson(
|
||||
ROYAL_POP_CART_KEY,
|
||||
items.map((item) => ({
|
||||
...item,
|
||||
quantity: Math.max(1, Math.round(Number(item.quantity) || 1)),
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
const getCartCount = () => loadCart().reduce((sum, item) => sum + Math.max(1, Number(item.quantity) || 1), 0);
|
||||
|
||||
const addSelectionToCart = (selection) => {
|
||||
const normalized = normalizeSelection(selection || {});
|
||||
const currentCart = loadCart();
|
||||
const matchingIndex = currentCart.findIndex(
|
||||
(item) =>
|
||||
item.style === normalized.style &&
|
||||
item.colorwayId === normalized.colorwayId &&
|
||||
item.finishId === normalized.finishId,
|
||||
);
|
||||
|
||||
let nextCart;
|
||||
if (matchingIndex >= 0) {
|
||||
nextCart = currentCart.map((item, index) =>
|
||||
index === matchingIndex
|
||||
? {
|
||||
...item,
|
||||
quantity: Math.max(1, Number(item.quantity) || 1) + normalized.quantity,
|
||||
}
|
||||
: item,
|
||||
);
|
||||
} else {
|
||||
nextCart = [
|
||||
...currentCart,
|
||||
{
|
||||
id: createItemId(),
|
||||
style: normalized.style,
|
||||
colorwayId: normalized.colorwayId,
|
||||
finishId: normalized.finishId,
|
||||
quantity: normalized.quantity,
|
||||
},
|
||||
];
|
||||
}
|
||||
saveCart(nextCart);
|
||||
|
||||
return {
|
||||
cart: nextCart,
|
||||
addedCount: normalized.quantity,
|
||||
isFull: false,
|
||||
};
|
||||
};
|
||||
|
||||
const removeCartItem = (itemId) => {
|
||||
const currentCart = loadCart();
|
||||
const nextCart = currentCart.filter((item) => item.id !== itemId);
|
||||
saveCart(nextCart);
|
||||
return nextCart;
|
||||
};
|
||||
|
||||
const getEffectiveCart = () => {
|
||||
const cart = loadCart();
|
||||
if (cart.length > 0) return cart;
|
||||
|
||||
const selection = loadBuilderSelection();
|
||||
if (!selection) return [];
|
||||
|
||||
return [{
|
||||
id: createItemId(),
|
||||
style: selection.style,
|
||||
colorwayId: selection.colorwayId,
|
||||
finishId: selection.finishId,
|
||||
quantity: selection.quantity,
|
||||
}];
|
||||
};
|
||||
|
||||
const groupCartItems = (items) => {
|
||||
const groups = new Map();
|
||||
|
||||
(items || []).forEach((item) => {
|
||||
const key = `${item.style}::${item.colorwayId}::${item.finishId}`;
|
||||
const current = groups.get(key);
|
||||
const itemQuantity = Math.max(1, Math.round(Number(item.quantity) || 1));
|
||||
|
||||
if (current) {
|
||||
current.quantity += itemQuantity;
|
||||
return;
|
||||
}
|
||||
|
||||
groups.set(key, {
|
||||
style: item.style,
|
||||
colorwayId: item.colorwayId,
|
||||
finishId: item.finishId,
|
||||
quantity: itemQuantity,
|
||||
});
|
||||
});
|
||||
|
||||
return Array.from(groups.values());
|
||||
};
|
||||
|
||||
const clearCart = () => {
|
||||
if (!isBrowser()) return;
|
||||
window.localStorage.removeItem(ROYAL_POP_CART_KEY);
|
||||
};
|
||||
|
||||
window.RoyalPopCart = {
|
||||
ROYAL_POP_CART_KEY,
|
||||
ROYAL_POP_BUILDER_KEY,
|
||||
ROYAL_POP_CART_LIMIT,
|
||||
loadBuilderSelection,
|
||||
saveBuilderSelection,
|
||||
loadCart,
|
||||
saveCart,
|
||||
getCartCount,
|
||||
addSelectionToCart,
|
||||
removeCartItem,
|
||||
getEffectiveCart,
|
||||
groupCartItems,
|
||||
clearCart,
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://royal-pop-accessory.com/</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://royal-pop-accessory.com/buy</loc>
|
||||
</url>
|
||||
</urlset>
|
||||