waybetter-for-x/apps/desktop/scripts/visual-bugs/x-fixture.mjs
2026-10-01 06:01:13 +07:00

336 lines
43 KiB
JavaScript

// X-shaped fixture pages for the visual-bug audit (scripts/visual-bugs.mjs). Unlike the theme
// matrix fixtures (color/contrast approximations), these reproduce the LAYOUT mechanics of x.com's
// markup, because the bugs they guard against are layout bugs: react-native-web's atomic classes
// with their real rules (`css-175oi2r` boxes never shrink unless `r-1wbh5a2` says so, the time box
// `r-1q142lx` never shrinks, names/handles ellipsize, headers are space-between rows with the
// Grok / ··· buttons on the right), X's testids and landmarks (User-Name, caret, role=group action
// bars, the focal post's "time · date · N Views" line, sidebar modules inside bordered cards,
// `chat-drawer-root` bottom right, the inline reply box) and X's width breakpoints (nav 275/88,
// right column only from 1000px, 290px below 1078, mobile bars below 500px).
// Passing here is not a live X test.
export const PALETTES = {
light: { bg: '#ffffff', text: 'rgb(15, 20, 25)', muted: 'rgb(83, 100, 113)', border: 'rgb(239, 243, 244)', accent: 'rgb(29, 155, 240)', hover: 'rgba(15, 20, 25, 0.1)', scheme: 'light' },
dark: { bg: '#000000', text: 'rgb(231, 233, 234)', muted: 'rgb(113, 118, 123)', border: 'rgb(47, 51, 54)', accent: 'rgb(29, 155, 240)', hover: 'rgba(231, 233, 234, 0.1)', scheme: 'dark' },
};
const X_CSS = `
html { font-size: 15px; -webkit-text-size-adjust: 100%; }
html, body { margin: 0; min-height: 100%; }
body { font-family: TwitterChirp, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; overflow-y: scroll; }
a { color: inherit; }
/* react-native-web base boxes (verbatim rules) */
.css-175oi2r { align-items: stretch; background-color: rgba(0,0,0,0); border: 0 solid black; box-sizing: border-box; display: flex; flex-basis: auto; flex-direction: column; flex-shrink: 0; list-style: none; margin: 0; min-height: 0; min-width: 0; padding: 0; position: relative; text-decoration: none; z-index: 0; }
.css-146c3p1 { background-color: rgba(0,0,0,0); border: 0 solid black; box-sizing: border-box; color: rgb(0,0,0); display: inline; font: 14px -apple-system, "system-ui", "Segoe UI", Roboto, Helvetica, Arial, sans-serif; list-style: none; margin: 0; padding: 0; position: relative; text-align: inherit; text-decoration: none; white-space: pre-wrap; overflow-wrap: break-word; }
.css-1jxf684 { background-color: rgba(0,0,0,0); border: 0 solid black; box-sizing: border-box; color: inherit; display: inline; font: inherit; list-style: none; margin: 0; padding: 0; position: relative; text-align: inherit; text-decoration: none; white-space: inherit; overflow-wrap: break-word; }
button.css-175oi2r { cursor: pointer; font: inherit; color: inherit; }
/* atomic classes used below (rule per class, as X ships them) */
.r-18u37iz { flex-direction: row; } .r-1wbh5a2 { flex-shrink: 1; } .r-1q142lx { flex-shrink: 0; } .r-dnmrzs { max-width: 100%; }
.r-1wtj0ep { justify-content: space-between; } .r-16y2uox { flex-grow: 1; } .r-1udh08x { overflow: hidden; } .r-bcqeeo { min-width: 0; }
.r-3s2u2q { white-space: nowrap; } .r-1udbk01 { text-overflow: ellipsis; } .r-qvutc0 { overflow-wrap: break-word; } .r-poiln3 { font-family: inherit; }
.r-37j5jr { font-family: TwitterChirp, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } .r-a023e6 { font-size: 15px; } .r-rjixqe { line-height: 20px; }
.r-1inkyih { font-size: 17px; } .r-16dba41 { font-weight: 400; } .r-b88u0q { font-weight: 700; } .r-adyw6z { font-size: 20px; } .r-135wba7 { line-height: 24px; }
.r-1awozwy { align-items: center; } .r-1d09ksm { align-items: baseline; } .r-k4xj1c { align-items: flex-start; } .r-xoduu5 { display: inline-flex; } .r-6koalj { display: flex; }
.r-s1qlax { padding-left: 4px; padding-right: 4px; } .r-13hce6t { margin-left: 4px; } .r-1kkk96v { margin-left: 8px; } .r-1h0z5md { justify-content: flex-start; } .r-1777fci { justify-content: center; }
.r-13awgt0 { flex: 1 1 0; } .r-sdzlij { border-radius: 9999px; } .r-1loqt21 { cursor: pointer; } .r-zl2h9q { margin-bottom: 2px; } .r-1s2bzr4 { margin-top: 12px; }
.r-18kxxzh { flex-basis: 40px; } .r-1wron08 { margin-right: 8px; } .r-1iusvr4 { flex-basis: 0; } .r-kzbkwu { padding-bottom: 12px; } .r-ttdzmv { padding-top: 12px; }
.r-1ny4l3l { outline-style: none; } .r-o7ynqc { transition-duration: .2s; } .r-clp7b1 { margin: -4px; } .r-1d2f490 { left: 0; } .r-u8s1d { position: absolute; }
.r-1ifxtd0 { margin-bottom: 16px; } .r-1phboty { border-style: solid; } .r-rs99b7 { border-width: 1px; } .r-1867qdf { border-radius: 16px; }
.r-gtdqiz { position: sticky; } .r-1hycxz { width: 350px; } .r-aqfbo4 { background-color: transparent; } .r-1xcajam { position: fixed; }
.r-1ye8kvj { max-width: 600px; } .r-kemksi { background-color: var(--x-bg); } .r-1kqtdi0 { border-color: var(--x-border); }
.r-qklmqi { border-bottom-width: 1px; } .r-1igl3o0 { border-bottom-style: solid; } .r-12kyg2d { margin-top: 16px; margin-bottom: 16px; }
.r-1a11zyx { position: relative; } .r-1b43r93 { font-size: 14px; } .r-1cwl3u0 { line-height: 16px; } .r-n6v787 { font-size: 13px; }
.r-1h3ijdo { height: 53px; } .r-ymttw5 { padding-left: 16px; padding-right: 16px; } .r-1w6e6rj { flex-wrap: wrap; }
svg.r-icon { width: 18.75px; height: 18.75px; fill: currentColor; flex-shrink: 0; }
/* page scaffolding (X's layout rules at each breakpoint) */
#react-root { display: flex; flex-direction: row; justify-content: center; min-height: 100vh; }
header[role="banner"] { display: flex; flex-grow: 1; align-items: flex-end; z-index: 3; }
header[role="banner"] > .nav { position: sticky; top: 0; height: 100vh; width: 275px; box-sizing: border-box; padding: 0 12px; gap: 4px; }
main[role="main"] { display: flex; flex-grow: 1; flex-shrink: 1; min-width: 0; align-items: flex-start; }
header[role="banner"] { flex-shrink: 0; }
main[role="main"] > div { width: 990px; }
[data-testid="primaryColumn"] { width: 100%; max-width: 600px; min-height: 100vh; border-left: 1px solid var(--x-border); border-right: 1px solid var(--x-border); flex-shrink: 1; }
[data-testid="sidebarColumn"] { width: 350px; margin-right: 10px; }
[data-testid="sidebarColumn"] .search-wrap { position: sticky; top: 0; padding: 4px 0 12px; background: var(--x-bg); z-index: 2; }
.fx-avatar { width: 40px; height: 40px; border-radius: 9999px; background: linear-gradient(135deg, #7856ff, #1d9bf0); flex-shrink: 0; }
.fx-media { margin-top: 12px; height: 180px; border-radius: 16px; border: 1px solid var(--x-border); background: linear-gradient(135deg, rgba(29,155,240,.35), rgba(120,86,255,.25)); }
.fx-banner { height: 150px; background: linear-gradient(135deg, #22303c, #1d9bf0); }
[data-testid="BottomBar"], [data-testid="TopNavBar"] { display: none; }
[data-testid="chat-drawer-root"] { position: fixed; right: 20px; bottom: 20px; z-index: 5; }
[data-testid="chat-drawer-root"] button { width: 56px; height: 56px; border-radius: 16px; border: 1px solid var(--x-border); background: var(--x-bg); box-shadow: 0 0 12px rgba(101,119,134,.25); align-items: center; justify-content: center; }
@media (max-width: 1264px) { header[role="banner"] > .nav { width: 88px; } .nav .fx-label { display: none; } }
/* X renders other width classes below 1078px (layout is JS-driven): 290px wide right column. */
.r-sb290 { width: 290px; }
@media (max-width: 1077px) { main[role="main"] > div { width: min(920px, calc(100vw - 105px)); } [data-testid="sidebarColumn"] { width: 290px; } }
@media (max-width: 999px) { main[role="main"] > div { width: 600px; } [data-testid="sidebarColumn"] { display: none; } }
@media (max-width: 699px) { main[role="main"] > div { width: 100%; } main[role="main"] { flex-grow: 1; } }
@media (max-width: 499px) {
header[role="banner"] { display: none; }
[data-testid="primaryColumn"] { border: 0; max-width: none; }
[data-testid="BottomBar"] { display: flex; position: fixed; left: 0; right: 0; bottom: 0; height: 53px; border-top: 1px solid var(--x-border); background: var(--x-bg); z-index: 4; flex-direction: row; justify-content: space-around; align-items: center; }
[data-testid="chat-drawer-root"] { bottom: 73px; }
}
`;
const ICON = {
reply: 'M1.751 10c0-4.42 3.584-8 8.005-8h4.366c4.49 0 8.129 3.64 8.129 8.13 0 2.96-1.607 5.68-4.196 7.11l-8.054 4.46v-3.69h-.067c-4.49.1-8.183-3.51-8.183-8.01z',
retweet: 'M4.5 3.88l4.432 4.14-1.364 1.46L5.5 7.55V16c0 1.1.896 2 2 2H13v2H7.5c-2.209 0-4-1.79-4-4V7.55L1.432 9.48.068 8.02 4.5 3.88zM16.5 6H11V4h5.5c2.209 0 4 1.79 4 4v8.45l2.068-1.93 1.364 1.46-4.432 4.14-4.432-4.14 1.364-1.46 2.068 1.93V8c0-1.1-.896-2-2-2z',
like: 'M16.697 5.5c-1.222-.06-2.679.51-3.89 2.16l-.805 1.09-.806-1.09C9.984 6.01 8.526 5.44 7.304 5.5c-1.243.07-2.349.78-2.91 1.91-.552 1.12-.633 2.78.479 4.82 1.074 1.97 3.257 4.27 7.129 6.61 3.87-2.34 6.052-4.64 7.126-6.61 1.111-2.04 1.03-3.7.477-4.82-.561-1.13-1.666-1.84-2.908-1.91z',
views: 'M8.75 21V3h2v18h-2zM18 21V8.5h2V21h-2zM4 21l.004-10h2L6 21H4zm9.248 0v-7h2v7h-2z',
bookmark: 'M4 4.5C4 3.12 5.119 2 6.5 2h11C18.881 2 20 3.12 20 4.5v18.44l-8-5.71-8 5.71V4.5z',
share: 'M12 2.59l5.7 5.7-1.41 1.42L13 6.41V16h-2V6.41l-3.3 3.3-1.41-1.42L12 2.59zM21 15l-.02 3.51c0 1.38-1.12 2.49-2.5 2.49H5.5C4.11 21 3 19.88 3 18.5V15h2v3.5c0 .28.22.5.5.5h12.98c.28 0 .5-.22.5-.5L19 15h2z',
caret: 'M3 12c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2zm9 2c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm7 0c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z',
grok: 'M2.205 7.423L11.745 21h4.241L6.446 7.423H2.204zm4.237 7.541L2.2 21h4.243l2.12-3.017-2.121-3.02zM16.957 0L9.624 10.435l2.122 3.02L21.2 0h-4.243zm.767 6.456V21H21.2V1.51l-3.476 4.946z',
chat: 'M1.998 5.5c0-1.381 1.119-2.5 2.5-2.5h15c1.381 0 2.5 1.119 2.5 2.5v13c0 1.381-1.119 2.5-2.5 2.5h-15c-1.381 0-2.5-1.119-2.5-2.5v-13z',
verified: 'M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-.607.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-.882-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 1.604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1.902-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 1.29.144 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02.647.218 1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 1.896.13.634.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 1.897-.136.274.586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 1.276-.213 1.817-.567s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 1.22-.447 1.68-.907.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 1.084-.705 1.439-1.246.354-.54.551-1.17.569-1.816z',
};
const svg = (d, extra = '') => `<svg viewBox="0 0 24 24" aria-hidden="true" class="r-icon"${extra}><g><path d="${d}"></path></g></svg>`;
const text = (content, color, cls = 'r-a023e6 r-rjixqe r-16dba41') => `<div dir="ltr" class="css-146c3p1 r-bcqeeo r-1ttztb7 r-qvutc0 r-37j5jr ${cls}" style="color: ${color};"><span class="css-1jxf684 r-bcqeeo r-1ttztb7 r-qvutc0 r-poiln3">${content}</span></div>`;
const iso = ago => new Date(Date.UTC(2026, 8, 29, 12, 0) - ago).toISOString();
function actionButton(p, testid, label, icon, count) {
return `<div class="css-175oi2r r-18u37iz r-1h0z5md r-13awgt0"><button aria-label="${count} ${label}. ${label}" role="button" class="css-175oi2r r-1777fci r-1loqt21 r-1ny4l3l" data-testid="${testid}" type="button" style="border:0;background:none;padding:0;">
<div dir="ltr" class="css-146c3p1 r-bcqeeo r-1ttztb7 r-qvutc0 r-37j5jr r-a023e6 r-rjixqe r-16dba41 r-1awozwy r-6koalj r-1h0z5md r-o7ynqc r-3s2u2q" style="color: ${p.muted};">
<div class="css-175oi2r r-xoduu5">${svg(icon)}</div>
<div class="css-175oi2r r-xoduu5 r-1udh08x" style="padding: 0 12px 0 4px;"><span data-testid="app-text-transition-container" style="transition-property: transform; transition-duration: 0.3s; transform: translate3d(0px, 0px, 0px);"><span class="css-1jxf684 r-1ttztb7 r-qvutc0 r-poiln3 r-n6v787 r-1cwl3u0"><span class="css-1jxf684 r-bcqeeo r-1ttztb7 r-qvutc0 r-poiln3">${count}</span></span></span></div>
</div></button></div>`;
}
function actionBar(p, handle, id, focal = false) {
const views = `<div class="css-175oi2r r-18u37iz r-1h0z5md r-13awgt0"><a href="/${handle}/status/${id}/analytics" aria-label="9123 views. View post analytics" role="link" class="css-175oi2r r-1777fci r-1loqt21 r-1ny4l3l" style="text-decoration:none">
<div dir="ltr" class="css-146c3p1 r-bcqeeo r-37j5jr r-a023e6 r-rjixqe r-1awozwy r-6koalj r-1h0z5md r-3s2u2q" style="color: ${p.muted};"><div class="css-175oi2r r-xoduu5">${svg(ICON.views)}</div><div class="css-175oi2r r-xoduu5 r-1udh08x" style="padding: 0 12px 0 4px;"><span data-testid="app-text-transition-container"><span class="css-1jxf684 r-n6v787 r-1cwl3u0"><span class="css-1jxf684">9.1K</span></span></span></div></div></a></div>`;
return `<div class="css-175oi2r"><div aria-label="12 replies, 3 reposts, 48 likes, 2 bookmarks, 9123 views" role="group" class="css-175oi2r r-18u37iz r-1wtj0ep r-1ye8kvj r-1s2bzr4" style="${focal ? `border-top: 1px solid var(--x-border); border-bottom: 1px solid var(--x-border); padding: 4px 4px; margin-top: 0;` : ''}">
${actionButton(p, 'reply', 'Replies', ICON.reply, '12')}
${actionButton(p, 'retweet', 'reposts', ICON.retweet, '3')}
${actionButton(p, 'like', 'Likes', ICON.like, '48')}
${focal ? '' : views}
<div class="css-175oi2r r-18u37iz r-1h0z5md" style="gap: 8px;"><div class="css-175oi2r r-18u37iz r-1h0z5md"><button aria-label="Bookmark" data-testid="bookmark" class="css-175oi2r r-1777fci" type="button" style="border:0;background:none;padding:0;color:${p.muted}">${svg(ICON.bookmark)}</button></div>
<div class="css-175oi2r r-18u37iz r-1h0z5md"><button aria-label="Share post" class="css-175oi2r r-1777fci" type="button" style="border:0;background:none;padding:0;color:${p.muted}">${svg(ICON.share)}</button></div></div>
</div></div>`;
}
/** X's header row: name block (User-Name) on the left, Grok / ··· on the right. */
function headerRow(p, { name, handle, id, ago, relative, verified = true }) {
return `<div class="css-175oi2r r-zl2h9q"><div class="css-175oi2r r-k4xj1c r-18u37iz r-1wtj0ep">
<div class="css-175oi2r r-1d09ksm r-18u37iz r-1wbh5a2"><div class="css-175oi2r r-1wbh5a2 r-dnmrzs r-1ny4l3l">
<div class="css-175oi2r r-1wbh5a2 r-dnmrzs r-1ny4l3l r-1awozwy r-18u37iz" data-testid="User-Name">
<div class="css-175oi2r r-1awozwy r-18u37iz r-1wbh5a2 r-dnmrzs"><div class="css-175oi2r r-1wbh5a2 r-dnmrzs"><a href="/${handle}" role="link" class="css-175oi2r r-1wbh5a2 r-dnmrzs r-1ny4l3l r-1loqt21"><div class="css-175oi2r r-1awozwy r-18u37iz r-dnmrzs">
<div dir="ltr" class="css-146c3p1 r-bcqeeo r-1ttztb7 r-qvutc0 r-37j5jr r-a023e6 r-rjixqe r-b88u0q r-1awozwy r-6koalj r-1udh08x r-3s2u2q" style="color: ${p.text};"><span class="css-1jxf684 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-bcqeeo r-1ttztb7 r-qvutc0 r-poiln3"><span class="css-1jxf684 r-bcqeeo r-1ttztb7 r-qvutc0 r-poiln3">${name}</span></span></div>
${verified ? `<div dir="ltr" class="css-146c3p1 r-bcqeeo r-37j5jr r-a023e6 r-rjixqe r-xoduu5 r-18u37iz r-1q142lx" style="color: ${p.text};"><span class="css-1jxf684 r-1awozwy r-xoduu5" style="margin-left:2px">${svg(ICON.verified, ' data-testid="icon-verified" aria-label="Verified account" style="color: rgb(29, 155, 240)"')}</span></div>` : ''}
</div></a></div></div>
<div class="css-175oi2r r-18u37iz r-1wbh5a2 r-13hce6t"><div class="css-175oi2r r-1d09ksm r-18u37iz r-1wbh5a2">
<div class="css-175oi2r r-1wbh5a2 r-dnmrzs"><a href="/${handle}" role="link" tabindex="-1" class="css-175oi2r r-1wbh5a2 r-dnmrzs r-1ny4l3l r-1loqt21"><div dir="ltr" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-bcqeeo r-1ttztb7 r-qvutc0 r-37j5jr r-a023e6 r-rjixqe r-16dba41 r-18u37iz" style="color: ${p.muted};"><span class="css-1jxf684 r-bcqeeo r-1ttztb7 r-qvutc0 r-poiln3">@${handle}</span></div></a></div>
<div dir="ltr" aria-hidden="true" class="css-146c3p1 r-bcqeeo r-1ttztb7 r-qvutc0 r-37j5jr r-a023e6 r-rjixqe r-16dba41 r-1q142lx r-s1qlax" style="color: ${p.muted};"><span class="css-1jxf684 r-bcqeeo r-1ttztb7 r-qvutc0 r-poiln3">·</span></div>
<div class="css-175oi2r r-18u37iz r-1q142lx"><a href="/${handle}/status/${id}" dir="ltr" aria-label="${relative}" role="link" class="css-146c3p1 r-bcqeeo r-1ttztb7 r-qvutc0 r-37j5jr r-a023e6 r-rjixqe r-16dba41 r-xoduu5 r-1q142lx r-3s2u2q r-1loqt21" style="color: ${p.muted}; text-decoration: none;"><time datetime="${iso(ago)}">${relative}</time></a></div>
</div></div>
</div>
</div></div>
<div class="css-175oi2r r-1kkk96v"><div class="css-175oi2r r-1awozwy r-18u37iz r-1wtj0ep"><div class="css-175oi2r r-1awozwy r-6koalj r-18u37iz" style="gap: 2px;">
<div class="css-175oi2r"><button aria-label="Grok actions" role="button" class="css-175oi2r r-1777fci r-1loqt21" type="button" style="border:0;background:none;padding:0;width:30px;height:20px;align-items:center;color:${p.muted}">${svg(ICON.grok)}</button></div>
<div class="css-175oi2r r-18u37iz r-1h0z5md"><button aria-haspopup="menu" aria-label="More" role="button" data-testid="caret" class="css-175oi2r r-1777fci r-1loqt21" type="button" style="border:0;background:none;padding:0;width:30px;height:20px;align-items:center;color:${p.muted}">${svg(ICON.caret)}</button></div>
</div></div></div>
</div></div>`;
}
export function tweet(p, post) {
const { name, handle, id, body, media = false, quote = null } = post;
return `<div data-testid="cellInnerDiv" class="css-175oi2r" style="position: relative;"><div class="css-175oi2r r-1igl3o0 r-qklmqi r-1kqtdi0"><div class="css-175oi2r">
<article aria-labelledby="id__${id}" role="article" tabindex="0" class="css-175oi2r r-18u37iz r-1udh08x r-1ny4l3l r-1loqt21" data-testid="tweet" style="padding: 0 16px;">
<div class="css-175oi2r r-16y2uox r-1wbh5a2"><div class="css-175oi2r r-16y2uox r-1wbh5a2 r-1ny4l3l">
<div class="css-175oi2r"><div class="css-175oi2r r-18u37iz"><div class="css-175oi2r r-1iusvr4 r-16y2uox r-ttdzmv"></div></div></div>
<div class="css-175oi2r r-18u37iz">
<div class="css-175oi2r r-18kxxzh r-1wron08"><div data-testid="Tweet-User-Avatar" class="css-175oi2r"><div class="fx-avatar"></div></div></div>
<div class="css-175oi2r r-1iusvr4 r-16y2uox r-kzbkwu">
${headerRow(p, post)}
<div class="css-175oi2r"><div dir="auto" lang="en" class="css-146c3p1 r-bcqeeo r-1ttztb7 r-qvutc0 r-37j5jr r-a023e6 r-rjixqe r-16dba41" data-testid="tweetText" style="color: ${p.text};"><span class="css-1jxf684 r-bcqeeo r-1ttztb7 r-qvutc0 r-poiln3">${body}</span></div></div>
${media ? `<div class="css-175oi2r"><a href="/${handle}/status/${id}/photo/1" class="fx-media" style="display:block"></a></div>` : ''}
${quote ? quoteCard(p, quote) : ''}
${actionBar(p, handle, id)}
</div>
</div>
</div></div>
</article></div></div></div>`;
}
function quoteCard(p, q) {
return `<div class="css-175oi2r" style="margin-top: 12px;"><div tabindex="0" role="link" class="css-175oi2r r-1udh08x r-1867qdf r-rs99b7 r-1phboty r-1kqtdi0" style="padding: 12px;">
<div class="css-175oi2r r-18u37iz" style="gap: 4px; align-items: center;"><div class="fx-avatar" style="width:20px;height:20px"></div>
<div class="css-175oi2r r-1wbh5a2 r-dnmrzs r-1awozwy r-18u37iz" data-testid="User-Name">
<div class="css-175oi2r r-1awozwy r-18u37iz r-1wbh5a2 r-dnmrzs">${text(`<span class="css-1jxf684 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q">${q.name}</span>`, p.text, 'r-a023e6 r-rjixqe r-b88u0q r-1udh08x r-3s2u2q r-6koalj')}</div>
<div class="css-175oi2r r-18u37iz r-1wbh5a2 r-13hce6t"><div class="css-175oi2r r-1d09ksm r-18u37iz r-1wbh5a2">
<div class="css-175oi2r r-1wbh5a2 r-dnmrzs">${text(`@${q.handle}`, p.muted, 'r-a023e6 r-rjixqe r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q')}</div>
<div dir="ltr" aria-hidden="true" class="css-146c3p1 r-37j5jr r-a023e6 r-rjixqe r-1q142lx r-s1qlax" style="color: ${p.muted};"><span class="css-1jxf684">·</span></div>
<div class="css-175oi2r r-18u37iz r-1q142lx"><div dir="ltr" class="css-146c3p1 r-37j5jr r-a023e6 r-rjixqe r-3s2u2q" style="color: ${p.muted};"><time datetime="${iso(q.ago)}">${q.relative}</time></div></div>
</div></div>
</div></div>
<div class="css-175oi2r" style="margin-top: 4px;">${text(q.body, p.text)}</div>
</div></div>`;
}
/** The opened post: name block stacked, full text, "time · date · N Views", action bar, reply box. */
function focalTweet(p, post, { own = false } = {}) {
const { name, handle, id, body, ago } = post;
const viewsInner = `<span class="css-1jxf684 r-bcqeeo r-1ttztb7 r-qvutc0 r-poiln3"><div class="css-175oi2r r-xoduu5 r-1udh08x"><span data-testid="app-text-transition-container"><span class="css-1jxf684 r-1ttztb7 r-qvutc0 r-poiln3"><span class="css-1jxf684 r-bcqeeo r-poiln3" style="color: ${p.text}; font-weight: 700;">1,234</span></span></span></div></span><span class="css-1jxf684 r-bcqeeo r-poiln3"> </span><span class="css-1jxf684 r-bcqeeo r-poiln3">Views</span>`;
const views = own
? `<a href="/${handle}/status/${id}/analytics" role="link" class="css-146c3p1 r-37j5jr r-a023e6 r-rjixqe r-1loqt21" style="color: ${p.muted}; text-decoration:none;">${viewsInner}</a>`
: `<div dir="ltr" class="css-146c3p1 r-bcqeeo r-37j5jr r-a023e6 r-rjixqe r-16dba41" style="color: ${p.muted};">${viewsInner}</div>`;
return `<div data-testid="cellInnerDiv" class="css-175oi2r"><div class="css-175oi2r"><div class="css-175oi2r">
<article aria-labelledby="id__f${id}" role="article" tabindex="-1" class="css-175oi2r r-18u37iz r-1udh08x r-1ny4l3l" data-testid="tweet" style="padding: 12px 16px 0;">
<div class="css-175oi2r r-16y2uox r-1wbh5a2"><div class="css-175oi2r r-16y2uox r-1wbh5a2">
<div class="css-175oi2r r-18u37iz">
<div class="css-175oi2r r-18kxxzh r-1wron08"><div class="fx-avatar"></div></div>
<div class="css-175oi2r r-1iusvr4 r-16y2uox"><div class="css-175oi2r r-k4xj1c r-18u37iz r-1wtj0ep">
<div class="css-175oi2r r-1wbh5a2 r-dnmrzs"><div class="css-175oi2r r-1wbh5a2 r-dnmrzs" data-testid="User-Name">
<div class="css-175oi2r r-1awozwy r-18u37iz r-dnmrzs"><a href="/${handle}" role="link" class="css-175oi2r r-1wbh5a2 r-dnmrzs r-1loqt21">${text(name, p.text, 'r-a023e6 r-rjixqe r-b88u0q r-3s2u2q')}</a>${svg(ICON.verified, ' data-testid="icon-verified" style="color: rgb(29, 155, 240); margin-left: 2px"')}</div>
<div class="css-175oi2r r-1wbh5a2 r-dnmrzs"><a href="/${handle}" role="link" tabindex="-1" class="css-175oi2r r-1wbh5a2 r-dnmrzs r-1loqt21" style="text-decoration:none">${text(`@${handle}`, p.muted)}</a></div>
</div></div>
<div class="css-175oi2r r-1kkk96v"><div class="css-175oi2r r-1awozwy r-18u37iz" style="gap: 2px;">
<div class="css-175oi2r"><button aria-label="Grok actions" class="css-175oi2r r-1777fci" type="button" style="border:0;background:none;padding:0;width:30px;height:20px;align-items:center;color:${p.muted}">${svg(ICON.grok)}</button></div>
<div class="css-175oi2r r-18u37iz r-1h0z5md"><button aria-haspopup="menu" aria-label="More" data-testid="caret" class="css-175oi2r r-1777fci" type="button" style="border:0;background:none;padding:0;width:30px;height:20px;align-items:center;color:${p.muted}">${svg(ICON.caret)}</button></div>
</div></div>
</div></div>
</div>
<div class="css-175oi2r" style="margin-top: 12px;"><div dir="auto" lang="en" class="css-146c3p1 r-bcqeeo r-1ttztb7 r-qvutc0 r-37j5jr r-1inkyih r-16dba41" data-testid="tweetText" style="color: ${p.text}; line-height: 24px;"><span class="css-1jxf684">${body}</span></div></div>
<div class="css-175oi2r r-12kyg2d"><div class="css-175oi2r r-1d09ksm r-18u37iz r-1wbh5a2" data-fx="meta">
<div class="css-175oi2r r-1wbh5a2 r-1a11zyx"><a href="/${handle}/status/${id}" dir="ltr" role="link" class="css-146c3p1 r-bcqeeo r-37j5jr r-a023e6 r-rjixqe r-16dba41 r-xoduu5 r-1q142lx r-3s2u2q r-1loqt21" style="color: ${p.muted}; text-decoration:none;"><time datetime="${iso(ago)}">10:06 PM · Sep 28, 2026</time></a></div>
<div dir="ltr" aria-hidden="true" class="css-146c3p1 r-bcqeeo r-37j5jr r-a023e6 r-rjixqe r-16dba41 r-1q142lx r-s1qlax" style="color: ${p.muted};"><span class="css-1jxf684">·</span></div>
<div class="css-175oi2r r-1wbh5a2 r-1a11zyx">${views}</div>
</div></div>
${actionBar(p, handle, id, true)}
<div class="css-175oi2r" style="padding: 12px 0;"><div class="css-175oi2r r-18u37iz" style="align-items: center; gap: 8px;">
<div class="fx-avatar"></div>
<div class="css-175oi2r r-16y2uox r-1wbh5a2" data-testid="tweetTextarea_0RichTextInputContainer"><div role="textbox" contenteditable="true" data-testid="tweetTextarea_0" aria-label="Post text" class="r-37j5jr" style="font-size: 20px; line-height: 24px; color: ${p.muted}; outline: none; padding: 8px 0;">Post your reply</div><div data-testid="attachments" class="css-175oi2r"></div></div>
<button data-testid="tweetButtonInline" role="button" class="css-175oi2r r-sdzlij" type="button" style="border:0;padding:0 16px;height:36px;align-items:center;justify-content:center;background:rgb(${p.scheme === 'dark' ? '239, 243, 244' : '15, 20, 25'});color:${p.scheme === 'dark' ? '#0f1419' : '#fff'};opacity:.5;font:700 15px/20px TwitterChirp, sans-serif">Reply</button>
</div></div>
</div></div>
</article></div></div></div>`;
}
function columnHeader(p, title, { back = false, tabs = [], sub = '' } = {}) {
return `<div class="css-175oi2r r-gtdqiz" style="top:0;z-index:3;backdrop-filter:blur(12px);background:color-mix(in srgb, var(--x-bg) 85%, transparent);border-bottom:1px solid var(--x-border)">
<div class="css-175oi2r r-1h3ijdo" style="padding: 0 16px; justify-content: center;"><div class="css-175oi2r r-18u37iz r-1awozwy" style="gap: 24px;">
${back ? `<div class="css-175oi2r"><button data-testid="app-bar-back" aria-label="Back" class="css-175oi2r" type="button" style="border:0;background:none;color:${p.text};width:34px;height:34px;align-items:center;justify-content:center">←</button></div>` : ''}
<div class="css-175oi2r r-16y2uox r-1wbh5a2"><h2 dir="ltr" aria-level="2" role="heading" class="css-146c3p1 r-bcqeeo r-37j5jr r-adyw6z r-135wba7 r-b88u0q" style="color: ${p.text}; margin: 0;"><span class="css-1jxf684">${title}</span></h2>${sub ? text(sub, p.muted, 'r-n6v787 r-1cwl3u0') : ''}</div>
</div></div>
${tabs.length ? `<nav role="navigation"><div role="tablist" class="css-175oi2r r-18u37iz">${tabs.map((t, i) => `<div role="presentation" class="css-175oi2r r-16y2uox"><a href="#" role="tab" aria-selected="${i === 0}" class="css-175oi2r r-1awozwy" style="padding: 16px 0; text-decoration:none">${text(t, i ? p.muted : p.text, i ? 'r-a023e6 r-rjixqe' : 'r-a023e6 r-rjixqe r-b88u0q')}</a></div>`).join('')}</div></nav>` : ''}
</div>`;
}
function homeComposer(p) {
return `<div class="css-175oi2r" style="padding: 12px 16px; border-bottom: 1px solid var(--x-border);"><div class="css-175oi2r r-18u37iz" style="gap: 8px;">
<div class="fx-avatar"></div>
<div class="css-175oi2r r-16y2uox r-1wbh5a2"><div data-testid="tweetTextarea_0RichTextInputContainer"><div role="textbox" contenteditable="true" data-testid="tweetTextarea_0" class="r-37j5jr" style="font-size: 20px; line-height: 24px; color: ${p.muted}; outline: none; padding: 8px 0;">What's happening?</div></div>
<div class="css-175oi2r r-18u37iz r-1wtj0ep r-1awozwy" style="margin-top: 8px;"><div data-testid="toolBar" class="css-175oi2r r-18u37iz"><div role="tablist" class="css-175oi2r r-18u37iz" style="gap: 12px; color: ${p.accent}">${[ICON.views, ICON.bookmark, ICON.chat, ICON.share].map(d => `<div role="presentation" class="css-175oi2r">${svg(d)}</div>`).join('')}</div></div>
<button data-testid="tweetButtonInline" class="css-175oi2r r-sdzlij" type="button" style="border:0;padding:0 16px;height:36px;align-items:center;justify-content:center;background:${p.accent};color:#fff;opacity:.5;font:700 15px/20px TwitterChirp, sans-serif">Post</button></div>
</div></div></div>`;
}
const POSTS = [
{ name: 'Servet Carey the Very Long Display Name', handle: 'Servet_Carey_Media', id: '2104386004480340100', ago: 2 * 3600e3, relative: '2h', body: 'Ezici üstünlük ile VLC Media Player çıktı. Gerçekten de çok kullanışlı, bazen hiç bir oynatıcının açmadığı videoları açan, hatalı videoları okuyabilen bir player.', media: true },
{ name: 'Lena Ortiz', handle: 'lena', id: '2104386004480340101', ago: 5 * 3600e3, relative: '5h', body: 'Shipping the new build tonight. Themes should never fight the layout.', quote: { name: 'Theo Park with a long quoted name', handle: 'theo_park_designs', ago: 26 * 3600e3, relative: 'Sep 27', body: 'The best interfaces feel inevitable once you see them.' } },
{ name: 'Mira', handle: 'mira', id: '2104386004480340102', ago: 3 * 86400e3, relative: 'Sep 26', body: 'Hot take: hover cards should be opaque. Always.' },
{ name: 'Jonas Weber', handle: 'jonas_weber', id: '2104386004480340103', ago: 400 * 86400e3, relative: 'Aug 25, 2025', body: 'Wrote 2k words on typographic rhythm and nobody asked.', media: true },
{ name: 'Sana Iqbal', handle: 'sana', id: '2104386004480340104', ago: 40 * 60e3, relative: '40m', body: 'Split panes at 1275px are the real stress test. crypto giveaway spam for the mute test.' },
];
const LONG = Array.from({ length: 150 }, (_, i) => ['reading', 'long', 'posts', 'in', 'a', 'narrow', 'pane', 'should', 'wrap', 'cleanly'][i % 10]).join(' ');
function sidebar(p, kind, width) {
const w = width >= 1078 ? 'r-1hycxz' : 'r-sb290';
const card = (inner) => `<div class="css-175oi2r r-1ifxtd0 r-1udh08x r-1kqtdi0 r-1phboty r-rs99b7 r-1867qdf">${inner}</div>`;
const heading = t => `<div class="css-175oi2r" style="padding: 12px 16px;"><h2 dir="ltr" aria-level="2" role="heading" class="css-146c3p1 r-37j5jr r-adyw6z r-135wba7 r-b88u0q" style="color:${p.text};margin:0"><span class="css-1jxf684">${t}</span></h2></div>`;
const premium = card(`<aside aria-label="Subscribe to Premium" role="complementary" class="css-175oi2r" style="padding: 12px 16px; gap: 8px;">${heading('Subscribe to Premium').replace('padding: 12px 16px;', 'padding: 0;')}${text('Subscribe to unlock new features and if eligible, receive a share of revenue.', p.text)}<a href="/i/premium_sign_up" role="link" class="css-175oi2r r-sdzlij" style="align-self:flex-start;background:${p.accent};color:#fff;padding:6px 16px;text-decoration:none;font:700 15px/20px TwitterChirp,sans-serif">Subscribe</a></aside>`);
const trends = card(`<section aria-labelledby="accessible-list-2" role="region" class="css-175oi2r"><h1 id="accessible-list-2" style="position:absolute;clip:rect(1px,1px,1px,1px);height:1px;overflow:hidden">Timeline: Trending now</h1><div aria-label="Timeline: Trending now" class="css-175oi2r"><div class="css-175oi2r">
${heading("What's happening")}
${['#wayBetter', 'Tauri 3', 'VLC', 'Split panes'].map((t, i) => `<div data-testid="cellInnerDiv" class="css-175oi2r"><div role="link" tabindex="0" data-testid="trend" class="css-175oi2r" style="padding: 12px 16px;">${text(`${i + 1} · Trending in Technology`, p.muted, 'r-n6v787 r-1cwl3u0')}${text(t, p.text, 'r-a023e6 r-rjixqe r-b88u0q')}${text(`${(i + 2) * 3}K posts`, p.muted, 'r-n6v787 r-1cwl3u0')}</div></div>`).join('')}
</div></div></section>`);
const people = label => card(`<aside aria-label="${label}" role="complementary" class="css-175oi2r">${heading(label)}<div class="css-175oi2r">${['Avery Stone', 'Kai Morgan'].map(n => `<button role="button" data-testid="UserCell" class="css-175oi2r" type="button" style="border:0;background:none;padding:12px 16px;text-align:left;color:${p.text}"><div class="css-175oi2r r-18u37iz r-1awozwy" style="gap:10px"><div class="fx-avatar"></div><div class="css-175oi2r r-16y2uox r-1wbh5a2">${text(n, p.text, 'r-a023e6 r-rjixqe r-b88u0q r-3s2u2q')}${text('@' + n.split(' ')[0].toLowerCase(), p.muted)}</div><div class="css-175oi2r r-sdzlij" style="background:${p.text};color:${p.bg};padding:6px 16px;font:700 14px/16px TwitterChirp,sans-serif">Follow</div></div></button>`).join('')}</div></aside>`);
const footer = `<nav aria-label="Footer" role="navigation" class="css-175oi2r r-18u37iz r-1w6e6rj r-ymttw5 r-1ifxtd0" style="gap: 4px 12px;">${['Terms of Service', 'Privacy Policy', 'Cookie Policy', 'Accessibility', 'Ads info', 'More ···', '© 2026 X Corp.'].map(t => text(t, p.muted, 'r-n6v787 r-1cwl3u0')).join('')}</nav>`;
const modules = {
home: [premium, trends, people('Who to follow')],
status: [people('Relevant people'), trends],
profile: [people('You might like'), trends],
notifications: [premium, trends, people('Who to follow')],
search: [people('Relevant people'), trends],
}[kind] ?? [trends];
return `<div data-testid="sidebarColumn" class="css-175oi2r"><div class="css-175oi2r ${w} r-16y2uox"><div class="css-175oi2r r-gtdqiz ${w}" style="top: 0;">
<div class="css-175oi2r ${w}">
<div class="css-175oi2r search-wrap"><form role="search" aria-label="Search" class="css-175oi2r"><div class="css-175oi2r r-sdzlij r-1phboty r-rs99b7 r-1kqtdi0 r-18u37iz r-1awozwy" style="padding: 10px 16px; gap: 12px; color: ${p.muted};">${svg(ICON.views)}<input data-testid="SearchBox_Search_Input" placeholder="Search" style="all:unset;flex:1;min-width:0;font:15px TwitterChirp,sans-serif;color:${p.text}"></div></form></div>
<div class="css-175oi2r ${w}">${modules.join('')}${footer}</div>
</div>
</div></div></div>`;
}
function nav(p) {
const items = [['Home', 'AppTabBar_Home_Link', '/home'], ['Explore', 'AppTabBar_Explore_Link', '/explore'], ['Notifications', 'AppTabBar_Notifications_Link', '/notifications'], ['Chat', 'AppTabBar_DirectMessage_Link', '/i/chat'], ['Bookmarks', 'AppTabBar_Bookmarks_Link', '/i/bookmarks'], ['Profile', 'AppTabBar_Profile_Link', '/CRTkafa']];
return `<header role="banner" class="css-175oi2r"><div class="css-175oi2r nav"><div class="css-175oi2r" style="padding-top: 8px; gap: 4px;">
<h1 role="heading" class="css-175oi2r" style="margin:0;padding:12px"><a href="/home" aria-label="X" role="link" class="css-175oi2r" style="width:28px;height:28px"><svg viewBox="0 0 24 24" aria-hidden="true" style="width:28px;height:28px;fill:${p.text}"><g><path d="M21.742 21.75l-7.563-11.179 7.056-8.321h-2.456l-5.691 6.714-4.54-6.714H2.359l7.29 10.776L2.25 21.75h2.456l6.035-7.118 4.818 7.118h6.191-.008zM7.739 3.818L18.81 20.182h-2.447L5.29 3.818h2.447z"></path></g></svg></a></h1>
<nav aria-label="Primary" role="navigation" class="css-175oi2r">${items.map(([label, testid, href]) => `<a href="${href}" data-testid="${testid}" aria-label="${label}" role="link" class="css-175oi2r r-18u37iz r-1awozwy r-sdzlij" style="padding:12px;gap:20px;text-decoration:none;color:${p.text}">${svg(ICON.chat, ' style="width:26px;height:26px"')}<span class="css-1jxf684 r-37j5jr r-adyw6z fx-label">${label}</span></a>`).join('')}
<button data-testid="AppTabBar_More_Menu" aria-label="More menu items" class="css-175oi2r r-18u37iz r-1awozwy r-sdzlij" type="button" style="border:0;background:none;padding:12px;gap:20px;color:${p.text}"><div class="css-175oi2r">${svg(ICON.caret, ' style="width:26px;height:26px"')}</div><div class="css-175oi2r fx-label"><span class="css-1jxf684 r-37j5jr r-adyw6z">More</span></div></button></nav>
</div></div></header>`;
}
function profileHead(p) {
return `<div class="fx-banner"></div><div class="css-175oi2r" style="padding: 12px 16px; gap: 8px;">
<div class="css-175oi2r r-18u37iz r-1wtj0ep" style="align-items:flex-end;margin-top:-60px"><div class="fx-avatar" style="width:120px;height:120px;border:4px solid var(--x-bg)"></div>
<div class="css-175oi2r r-18u37iz" style="gap:8px"><button data-testid="userActions" aria-label="More" class="css-175oi2r r-sdzlij" type="button" style="border:1px solid var(--x-border);background:none;width:36px;height:36px;align-items:center;justify-content:center;color:${p.text}">${svg(ICON.caret)}</button><button data-testid="1234-follow" class="css-175oi2r r-sdzlij" type="button" style="border:0;background:${p.text};color:${p.bg};padding:0 16px;height:36px;font:700 15px/20px TwitterChirp,sans-serif">Follow</button></div></div>
<div data-testid="UserName" class="css-175oi2r"><div class="css-175oi2r r-18u37iz r-1awozwy">${text('Placeholder User With A Long Name', p.text, 'r-adyw6z r-135wba7 r-b88u0q')}</div>${text('@placeholder', p.muted)}</div>
<div data-testid="UserDescription" class="css-175oi2r">${text('Designer. Writes about interfaces that stay out of the way. Split panes enthusiast.', p.text)}</div>
<div class="css-175oi2r r-18u37iz r-1w6e6rj" style="gap: 4px 20px;">
<a href="/placeholder/following" dir="ltr" role="link" class="css-146c3p1 r-37j5jr r-a023e6 r-rjixqe" style="color:${p.muted};text-decoration:none"><span class="css-1jxf684 r-b88u0q" style="color:${p.text}"><span class="css-1jxf684">412</span></span><span class="css-1jxf684"> <span class="css-1jxf684">Following</span></span></a>
<a href="/placeholder/verified_followers" dir="ltr" role="link" class="css-146c3p1 r-37j5jr r-a023e6 r-rjixqe" style="color:${p.muted};text-decoration:none"><span class="css-1jxf684 r-b88u0q" style="color:${p.text}"><span class="css-1jxf684">12.8K</span></span><span class="css-1jxf684"> <span class="css-1jxf684">Followers</span></span></a>
</div></div>`;
}
function notificationItem(p, i) {
return `<div data-testid="cellInnerDiv" class="css-175oi2r"><div class="css-175oi2r r-1igl3o0 r-qklmqi r-1kqtdi0"><article data-testid="notification" role="article" tabindex="0" class="css-175oi2r r-18u37iz" style="padding: 12px 16px; gap: 12px;">
<div class="css-175oi2r" style="width:40px;align-items:flex-end;color:rgb(249,24,128)">${svg(ICON.like, ' style="width:28px;height:28px"')}</div>
<div class="css-175oi2r r-16y2uox r-1wbh5a2" style="gap:8px"><div class="fx-avatar" style="width:32px;height:32px"></div>${text(`<b>Person ${i}</b> and ${i + 2} others liked your post`, p.text)}${text('Split panes at 1275px are the real stress test.', p.muted)}</div>
</article></div></div>`;
}
const ROUTES = {
home: { path: '/home', primary: p => `${columnHeader(p, 'Home', { tabs: ['For you', 'Following'] })}${homeComposer(p)}<section aria-labelledby="accessible-list-0" role="region" class="css-175oi2r"><div aria-label="Timeline: Your Home Timeline" class="css-175oi2r">${POSTS.map(post => tweet(p, post)).join('')}</div></section>` },
status: {
path: '/CRTkafa/status/2104386004480340200',
primary: p => `${columnHeader(p, 'Post', { back: true })}<section aria-labelledby="accessible-list-1" role="region" class="css-175oi2r"><div aria-label="Timeline: Conversation" class="css-175oi2r">
${tweet(p, POSTS[0])}
${focalTweet(p, { name: 'CRTkafa', handle: 'CRTkafa', id: '2104386004480340200', ago: 90 * 60e3, body: `Sıralama doğru. PotPlayer kim yahu. ${LONG}` }, { own: true })}
${tweet(p, { ...POSTS[2], name: 'CRTkafa', handle: 'CRTkafa', id: '2104386004480340201', body: 'A reply by the same author, so this is a thread.' })}
${POSTS.slice(1, 4).map(post => tweet(p, post)).join('')}
</div></section>`,
},
'status-other': {
path: '/lena/status/2104386004480340300',
primary: p => `${columnHeader(p, 'Post', { back: true })}<section role="region" class="css-175oi2r"><div aria-label="Timeline: Conversation" class="css-175oi2r">
${focalTweet(p, { name: 'Lena Ortiz', handle: 'lena', id: '2104386004480340300', ago: 90 * 60e3, body: 'Somebody else\'s post: views are plain text, not a link.' })}
${POSTS.slice(2, 5).map(post => tweet(p, post)).join('')}
</div></section>`,
},
profile: { path: '/placeholder', primary: p => `${columnHeader(p, 'Placeholder User With A Long Name', { back: true, sub: '1,024 posts' })}${profileHead(p)}<nav role="navigation"><div role="tablist" class="css-175oi2r r-18u37iz" style="border-bottom:1px solid var(--x-border)">${['Posts', 'Replies', 'Highlights', 'Articles', 'Media', 'Likes'].map((t, i) => `<div role="presentation" class="css-175oi2r r-16y2uox"><a href="/placeholder${i ? '/' + t.toLowerCase() : ''}" role="tab" aria-selected="${!i}" class="css-175oi2r r-1awozwy" style="padding:16px 0;text-decoration:none">${text(t, i ? p.muted : p.text)}</a></div>`).join('')}</div></nav>${POSTS.slice(0, 4).map(post => tweet(p, { ...post, name: 'Placeholder User With A Long Name', handle: 'placeholder' })).join('')}` },
notifications: { path: '/notifications', primary: p => `${columnHeader(p, 'Notifications', { tabs: ['All', 'Verified', 'Mentions'] })}${[1, 2].map(i => notificationItem(p, i)).join('')}${POSTS.slice(1, 4).map(post => tweet(p, post)).join('')}` },
search: { path: '/search?q=vlc&src=typed_query', primary: p => `<div class="css-175oi2r r-gtdqiz" style="top:0;z-index:3;background:var(--x-bg);border-bottom:1px solid var(--x-border)"><div class="css-175oi2r r-18u37iz r-1awozwy" style="padding:6px 16px;gap:12px"><button data-testid="app-bar-back" class="css-175oi2r" type="button" style="border:0;background:none;color:${p.text}">←</button><form role="search" aria-label="Search" class="css-175oi2r r-16y2uox"><div class="css-175oi2r r-sdzlij r-1phboty r-rs99b7 r-1kqtdi0" style="padding:8px 16px"><input data-testid="SearchBox_Search_Input" value="vlc" style="all:unset;font:15px TwitterChirp,sans-serif;color:${p.text}"></div></form><button aria-label="More" class="css-175oi2r" type="button" style="border:0;background:none;color:${p.text}">${svg(ICON.caret)}</button></div><div role="tablist" class="css-175oi2r r-18u37iz">${['Top', 'Latest', 'People', 'Media', 'Lists'].map((t, i) => `<div role="presentation" class="css-175oi2r r-16y2uox"><a href="#" role="tab" aria-selected="${!i}" class="css-175oi2r r-1awozwy" style="padding:14px 0;text-decoration:none">${text(t, i ? p.muted : p.text)}</a></div>`).join('')}</div></div>${POSTS.map(post => tweet(p, post)).join('')}` },
media: { path: '/placeholder/media', primary: p => `${columnHeader(p, 'Placeholder User', { back: true })}<section role="region" class="css-175oi2r"><div class="css-175oi2r"><div data-testid="cellInnerDiv" class="css-175oi2r"><div class="css-175oi2r r-18u37iz" style="flex-wrap:wrap">${Array.from({ length: 9 }, (_, i) => `<li class="css-175oi2r" style="width:33.33%;padding:2px;list-style:none;box-sizing:border-box"><a href="/placeholder/status/1${i}/photo/1" class="fx-media" style="display:block;margin:0;height:120px;border-radius:0"></a></li>`).join('')}</div></div></div></section>` },
};
export const ROUTE_NAMES = Object.keys(ROUTES);
export const routePath = route => ROUTES[route].path;
export function fixtureHtml(route, mode, width = 1280) {
const p = PALETTES[mode];
const r = ROUTES[route];
const sidebarKind = route.startsWith('status') ? 'status' : route === 'media' ? 'profile' : route;
return `<!doctype html><html lang="en" dir="ltr" style="font-size: 15px; color-scheme: ${p.scheme};"><head><meta charset="utf-8"><meta name="theme-color" content="${p.bg}"><title>X fixture / X</title>
<style>:root { --x-bg: ${p.bg}; --x-border: ${p.border}; }${X_CSS}</style></head>
<body style="background-color: ${p.bg};">
<div id="react-root">
${nav(p)}
<main role="main" class="css-175oi2r"><div class="css-175oi2r"><div class="css-175oi2r r-18u37iz r-1wtj0ep">
<div data-testid="primaryColumn" class="css-175oi2r">${r.primary(p)}</div>
${sidebar(p, sidebarKind, width)}
</div></div></main>
</div>
<div data-testid="BottomBar" class="css-175oi2r">${['Home', 'Search', 'Notifications', 'Chat'].map(() => `<div style="color:${p.text}">${svg(ICON.chat)}</div>`).join('')}</div>
<div data-testid="chat-drawer-root" class="css-175oi2r"><button aria-label="Chat" class="css-175oi2r" type="button" style="color:${p.text}">${svg(ICON.chat, ' style="width:24px;height:24px"')}</button></div>
<div id="layers"></div>
</body></html>`;
}