Jacob Kepler for BI
Lisa Lin had long worked alongside coders. When she had her son, she tried it for herself.
The 33-year-old has worked in operations roles at a variety of tech companies, including Uber. But she was “non-technical,” as her industry would call it; she couldn’t code.
Then came the AI revolution, and her baby. Lin moved from a full-time operations role to a contractor while taking on the new job of stay-at-home mom.
She’d heard horror stories about those early months, but has been pleasantly surprised. “He’s a happy baby,” she said.
When her baby was about 5 months old, she began testing out nutritional apps to introduce solid foods and identify allergens. She tried a popular nutrition app but found it overwhelming. “Day to day, it’s a lot of information to digest,” she said.
‘
).join(”);
root.innerHTML = `
${captionHtml}
`;
const msgsEl = document.getElementById(‘messages’);
(cfg.messages || []).forEach((m, i) => {
if (m.role === ‘divider’) {
const d = document.createElement(‘div’);
d.className = ‘divider’;
d.style.transitionDelay = (Math.min(i, 6) * 80) + ‘ms’;
d.innerHTML = m.label ? ‘‘ + esc(m.label) + ‘‘ : ”;
msgsEl.appendChild(d);
return;
}
const row = document.createElement(‘div’);
row.className = ‘msg-row’;
row.style.transitionDelay = (Math.min(i, 6) * 80) + ‘ms’;
row.dataset.index = i;
const msgDiv = document.createElement(‘div’);
msgDiv.className = ‘msg ‘ + (m.role === ‘user’ ? ‘user’ : ‘assistant’);
const markerHtml = m._noteNum
? ‘‘ + m._noteNum + ‘‘
: ”;
if (m.image) {
const cap = m.caption ? ‘
‘ : ”;
if (m.role === ‘user’) {
msgDiv.innerHTML =
‘
‘
cap +
‘
‘ + markerHtml;
} else {
msgDiv.innerHTML =
markerHtml +
‘
‘
cap +
‘
‘;
}
} else {
const bodyHtml = renderText(m.text || ”);
if (m.role === ‘user’) {
msgDiv.innerHTML = ‘
‘ + markerHtml;
} else {
msgDiv.innerHTML = markerHtml + ‘
‘;
}
}
row.appendChild(msgDiv);
// Inline note for mobile — placed before the annotated message
if (m.note) {
const inlineNote = document.createElement(‘div’);
inlineNote.className = ‘note-inline msg-row’;
inlineNote.style.transitionDelay = (Math.min(i, 6) * 80) + ‘ms’;
inlineNote.innerHTML = esc(m.note);
msgsEl.appendChild(inlineNote);
}
msgsEl.appendChild(row);
});
// Animate in
const items = msgsEl.querySelectorAll(‘.msg-row, .divider’);
const sideNotes = document.querySelectorAll(‘.note-sidebar’);
if (‘IntersectionObserver’ in window) {
const io = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.classList.add(‘in’);
// Also reveal matching sidebar note
const idx = e.target.dataset && e.target.dataset.index;
if (idx !== undefined) {
const sn = document.querySelector(‘.note-sidebar[data-for=”‘ + idx + ‘”]’);
if (sn) sn.classList.add(‘in’);
}
io.unobserve(e.target);
}
});
}, { root: msgsEl, threshold: 0.15, rootMargin: ‘0px 0px -20px 0px’ });
items.forEach(el => io.observe(el));
requestAnimationFrame(() => {
const cr = msgsEl.getBoundingClientRect();
items.forEach(el => {
const r = el.getBoundingClientRect();
if (r.top < cr.bottom && r.bottom > cr.top) {
el.classList.add(‘in’);
const idx = el.dataset && el.dataset.index;
if (idx !== undefined) {
const sn = document.querySelector(‘.note-sidebar[data-for=”‘ + idx + ‘”]’);
if (sn) sn.classList.add(‘in’);
}
io.unobserve(el);
}
});
});
} else {
items.forEach(el => el.classList.add(‘in’));
sideNotes.forEach(el => el.classList.add(‘in’));
}
// Show sidebar notes after a short delay
setTimeout(() => {
document.querySelectorAll(‘.note-sidebar’).forEach(el => el.classList.add(‘in’));
}, 600);
function esc(s) {
return String(s).replace(/[&<>”‘]/g, c => ({
‘&’:’&’,'<‘:'<‘,’>’:’>’,'”‘:'”‘,”‘”:”’
}[c]));
}
// Render text with hanging indent on bulleted lines
function renderText(s) {
const lines = String(s).split(‘n’);
return lines.map(line => {
if (line.trim() === ”) {
return ‘ ‘;
}
// Detect leading whitespace and bullet character
const m = line.match(/^(s*)([•◦●○-*])s+(.*)$/);
if (m) {
const ws = m[1].length;
const depth = ws >= 8 ? 2 : 1;
return ‘‘ + esc(m[2] + ‘ ‘ + m[3]) + ‘‘;
}
// Indented non-bullet line
const indentMatch = line.match(/^(s+)(.*)$/);
if (indentMatch && indentMatch[2]) {
return ‘‘ + esc(indentMatch[2]) + ‘‘;
}
return ‘‘ + esc(line) + ‘‘;
}).join(”);
}
})();