← back to Dw Domain Fleet
shared/sort.js
69 lines
/**
* sort.js — server-side product sorting + color-dot derivation for fleet sites.
*/
const COLOR_RANK = {
black:0,charcoal:1,gray:2,grey:2,silver:3,white:4,ivory:5,cream:6,beige:7,taupe:8,tan:9,brown:10,
red:20,coral:21,pink:22,salmon:23,rose:24,
orange:30,peach:31,apricot:32,
yellow:40,gold:41,mustard:42,ochre:43,
olive:50,green:51,lime:52,mint:53,
teal:60,aqua:61,turquoise:62,
blue:70,navy:71,indigo:72,periwinkle:73,
purple:80,violet:81,lavender:82,plum:83,magenta:84,fuchsia:85
};
const COLOR_HEX = {
black:'#0a0a0a',charcoal:'#2a2a2a',gray:'#888',grey:'#888',silver:'#c0c0c0',white:'#fafafa',
ivory:'#fffff0',cream:'#f5e9c8',beige:'#e7d6b6',taupe:'#b8a78f',tan:'#c9a36a',
brown:'#6b4a2b',chestnut:'#5a3825',
red:'#c92a2a',coral:'#e87a6b',pink:'#e6a4b4',salmon:'#e08e7c',rose:'#d68a9a',
orange:'#e07a32',peach:'#f0bb96',apricot:'#e0a373',
yellow:'#e8c84a',gold:'#d4af37',mustard:'#caa53d',ochre:'#b88c3a',
olive:'#7a7a36',green:'#3d8a4f',lime:'#92c84a',mint:'#aedcc1',
teal:'#2a8a8a',aqua:'#3ab4b4',turquoise:'#3ab8b0',
blue:'#3a5fb8',navy:'#1a2c52',indigo:'#37327a',periwinkle:'#8a93d4',
purple:'#6a3a8a',violet:'#7a4aa8',lavender:'#b0a3d6',plum:'#693a55',magenta:'#c5358a',fuchsia:'#d63aaf'
};
const STYLE_TAGS = ['traditional','transitional','modern','contemporary','minimalist','art deco',
'victorian','mid-century','rustic','industrial','bohemian','geometric','floral','botanical',
'damask','toile','grasscloth','silk','linen','vinyl','natural','abstract','stripe','textured'];
function colorRank(p) {
const tags = (p.tags || []).map(t => String(t).toLowerCase());
for (const t of tags) for (const k of Object.keys(COLOR_RANK)) if (t.includes(k)) return COLOR_RANK[k];
return 999;
}
function styleKey(p) {
const tags = (p.tags || []).map(t => String(t).toLowerCase());
for (const s of STYLE_TAGS) if (tags.some(t => t.includes(s))) return s;
return 'zzz';
}
function dominantHex(p) {
const tags = (p.tags || []).map(t => String(t).toLowerCase());
for (const t of tags) for (const k of Object.keys(COLOR_HEX)) if (t.includes(k)) return COLOR_HEX[k];
return '#9a9a9a';
}
function lum(hex) {
const m = /^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i.exec(hex || '');
if (!m) return 0.5;
const [r,g,b] = [1,2,3].map(i => parseInt(m[i],16)/255);
return 0.2126*r + 0.7152*g + 0.0722*b;
}
function sortProducts(list, mode) {
const a = list.slice();
switch (mode) {
case 'color': return a.sort((x,y) => colorRank(x) - colorRank(y));
case 'light-dark': return a.sort((x,y) => lum(dominantHex(y)) - lum(dominantHex(x)));
case 'dark-light': return a.sort((x,y) => lum(dominantHex(x)) - lum(dominantHex(y)));
case 'style': return a.sort((x,y) => styleKey(x).localeCompare(styleKey(y)));
case 'sku': return a.sort((x,y) => (x.sku||x.handle).localeCompare(y.sku||y.handle));
case 'title': return a.sort((x,y) => (x.title||'').localeCompare(y.title||''));
case 'price-asc': return a.sort((x,y) => parseFloat(x.price||0) - parseFloat(y.price||0));
case 'price-desc': return a.sort((x,y) => parseFloat(y.price||0) - parseFloat(x.price||0));
case 'newest':
default: return a.sort((x,y) => String(y.created_at).localeCompare(String(x.created_at)));
}
}
module.exports = { sortProducts, dominantHex, colorRank, styleKey };