// Mockups localizados — KLEO · INGRID · BoXtore · ZUBEHÖRE
// Todos los textos visibles cambian con el selector de idioma.
(function () {
const head = '"Poppins", system-ui, sans-serif';
const body = '"Inter", system-ui, sans-serif';
const mono = '"JetBrains Mono", ui-monospace, monospace';
const NAVY = '#0D1B2A';
const G = '#1F8A5B';
const A = '#E07B39';
// ── useLang helper ────────────────────────────────────────────
function useLang() {
const [, rerender] = React.useState(0);
React.useEffect(() => {
const h = () => rerender(n => n + 1);
window.addEventListener('langchange', h);
return () => window.removeEventListener('langchange', h);
}, []);
}
// Mock text data is loaded from mock-data.js → window.BX_MOCK / window.getMk()
// ── Phone frame ───────────────────────────────────────────────
const Phone = ({ accent, children, screen = '#fff' }) => (
);
// ── KLEO ─────────────────────────────────────────────────────
function KLEO({ accent }) {
useLang();
const P = accent;
const { useState, useEffect } = React;
const [activeTab, setActiveTab] = useState(0);
const [scrollIdx, setScrollIdx] = useState(0);
const mk = window.getMk().kleo;
useEffect(() => {
const t = setInterval(() => setActiveTab(n => (n + 1) % 4), 3600);
return () => clearInterval(t);
}, []);
useEffect(() => {
const t = setInterval(() => setScrollIdx(n => n + 1), 2200);
return () => clearInterval(t);
}, []);
const resolveColor = (cl) => cl === 'P' ? P : cl;
const visibleTasks = [0,1,2,3].map(i => mk.tasks[(scrollIdx + i) % mk.tasks.length]);
return (
{mk.stat_labels.map(([v, l, c]) => (
))}
{mk.tabs.map((t, i) => (
{t}
))}
{mk.pending}
{visibleTasks.map((task, i) => (
{task.ic}
{task.tag &&
{task.tag}}
))}
{mk.habits_label}
{mk.habits.map(([t, v, pct]) => (
))}
{mk.stats_row.map(([v, l, c]) => (
))}
);
}
// ── INGRID ───────────────────────────────────────────────────
function INGRID({ accent }) {
useLang();
const { useState, useEffect } = React;
const [visible, setVisible] = useState(2);
const [typing, setTyping] = useState(false);
const mk = window.getMk().ingrid;
useEffect(() => {
const cycle = () => {
setTyping(true);
setTimeout(() => { setTyping(false); setVisible(v => v < mk.messages.length ? v + 1 : 2); }, 1400);
};
const t = setInterval(cycle, 3200);
return () => clearInterval(t);
}, [mk.messages.length]);
const In = ({ children }) => (
{children}
);
const Out = ({ children }) => (
{children}
);
return (
{mk.messages.slice(0, visible).map(([isOut, text], i) =>
isOut ?
{text} :
{text}
)}
{typing && (
{[0,1,2].map(i => )}
)}
);
}
// ── BoXtore ──────────────────────────────────────────────────
function BoXtore({ accent }) {
useLang();
const { useState, useEffect } = React;
const B = '#0F1C2B', PAN = '#162436', S = '#1E3048';
const T = '#E8EFF8', DIM = 'rgba(232,239,248,0.5)';
const GG = '#1F8A5B', AA = '#E07B39';
const [activeNav, setActiveNav] = useState(0);
const [activeBar, setActiveBar] = useState(4);
const mk = window.getMk().bx;
// Status color map
const statusColor = { 'Completado': GG, 'Concluído': GG, 'Completed': GG, 'Complété': GG,
'En camino': accent, 'On the way': accent, 'En route': accent, 'A caminho': accent,
'Pendiente': AA, 'Pending': AA, 'En attente': AA, 'Pendente': AA };
function sc(s) { return statusColor[s] || accent; }
useEffect(() => {
const t1 = setInterval(() => setActiveBar(b => (b + 1) % 7), 700);
const t2 = setInterval(() => setActiveNav(n => (n + 1) % mk.nav.length), 3000);
return () => { clearInterval(t1); clearInterval(t2); };
}, [mk.nav.length]);
const bars = [38, 55, 42, 68, 85, 52, 76];
const views = {
0: () => (
<>
{mk.stats.map(([l,v,d]) => (
))}
{mk.sales7}
{['L','M','X','J','V','S','D'].map(d =>
{d}
)}
{mk.recent}
{mk.orders.slice(0,3).map(([id,n,s,a]) => (
{id}
{n}
{s}
{a}
))}
>
),
1: () => (
{mk.all_orders}
{mk.orders.map(([id,n,s,a,d]) => (
{id}
{n}
{s}
{d}
{a}
))}
),
2: () => (
{mk.clients_title}
{mk.clients.map(([ini,n,tel,p]) => (
))}
),
3: () => (
{mk.catalog.map(([n,p,s]) => (
))}
),
4: () => (
{mk.pos_ticket}
{mk.pos_items.map(([n,q,p]) => (
{n}
{q}
{p}
))}
{mk.pos_total}
$1,500
{mk.pos_cash}
{mk.pos_card}
{mk.pos_transfer}
),
5: () => (
{mk.monthly}
{mk.monthly_stats.map(([l,v]) => (
))}
{[42,58,35,70,85,62,78,55,90,72,68,80].map((h,i) => (
))}
{mk.months.map(m => (
{m}
))}
),
6: () => (
{mk.config_title}
{mk.config_fields.map(([l,v]) => (
{l}
{v}
))}
),
};
const ViewComponent = views[activeNav] || views[0];
return (
{['#FF5F57','#FEBC2E','#28C840'].map(c =>
)}
boxtore.britxia.tech
BoXtore
{mk.nav.map(([ic,label], i) => (
{ic}
{label}
))}
{mk.nav[activeNav][1]}
{mk.date}
{mk.new_btn}
);
}
// ── ZUBEHÖRE ─────────────────────────────────────────────────
function ZUBEHORE({ accent }) {
useLang();
const { useState, useEffect } = React;
const E = accent, EL = '#C7A06A', B = '#0F1A24', PAN = '#152030', S = '#1C2E3D';
const T = '#EDE8E0', DIM = 'rgba(237,232,224,0.5)';
const GG = '#1F8A5B', AA = '#E07B39';
const [activeNav, setActiveNav] = useState(0);
const [progPct, setProgPct] = useState([0,0,0]);
const mk = window.getMk().zu;
const statusColor = { 'En proceso': GG, 'En cours': GG, 'In progress': GG, 'Em andamento': GG,
'Agendado': EL, 'Scheduled': EL, 'Planifié': EL,
'Pendiente': AA, 'Pending': AA, 'En attente': AA, 'Pendente': AA };
function sc(s) { return statusColor[s] || E; }
useEffect(() => {
setTimeout(() => setProgPct([72,35,15]), 400);
const t = setInterval(() => setActiveNav(n => (n+1) % mk.nav.length), 3000);
return () => clearInterval(t);
}, [mk.nav.length]);
const views = {
0: () => (
<>
{mk.stats.map(([l,v]) => (
))}
{mk.active}
{mk.projects.map(([n,tp,st],i) => (
))}
{mk.today}
{mk.schedule.slice(0,3).map(([t,l,c]) => (
))}
>
),
1: () => (
{mk.nav[1][1]}
{mk.projects_all.map(([n,tp,st,pct]) => (
))}
),
2: () => (
{mk.nav[2][1]}
{mk.quotes.map(([id,n,m,s]) => (
{id}
{n}
{m}
{mk.quote_sc[s]||s}
))}
),
3: () => (
{mk.nav[3][1]}
{mk.clients.map(([ini,n,tel,p]) => (
))}
),
4: () => (
{mk.days.map((d,i) =>
{d}
)}
{[16,17,18,19,20,21,22].map(d => (
{d}
))}
{mk.schedule_title}
{mk.schedule.map(([t,l,tp],i) => (
))}
),
5: () => (
{mk.finance_title}
{mk.finance_stats.map(([l,v]) => (
))}
{mk.finance_items.map(([n,m,s]) => (
{n}
{m}
{mk.finance_sc[s]||s}
))}
),
6: () => (
{mk.config_title}
{mk.config_fields.map(([l,v]) => (
{l}
{v}
))}
),
};
const ViewComponent = views[activeNav] || views[0];
return (
{['#FF5F57','#FEBC2E','#28C840'].map(c =>
)}
zubehore.britxia.tech
ZUBEHÖRE
{mk.nav.map(([ic,l],i) => (
{ic}
{l}
))}
{mk.nav[activeNav][1]}
{mk.date}
{mk.new_btn}
{/* Mini phone overlay */}
{mk.mini_proj.map(([n,s,c]) => (
))}
);
}
window.Mockups = { KLEO, INGRID, BoXtore, 'ZUBEHÖRE': ZUBEHORE };
})();