README: a hero that shows the app
This commit is contained in:
parent
467aea2e28
commit
89c9bfc75f
32 changed files with 933 additions and 71 deletions
|
|
@ -12,6 +12,8 @@ const POST = 'article[data-testid="tweet"]';
|
|||
const COLUMN = '[data-testid="primaryColumn"]';
|
||||
/** The main column on every route but chat (a drawn bar above X's chat app would push its composer out of the window). */
|
||||
// Keyed on the engine's page flag (THEME_FLAGS in theme.ts), never `:has()` over the page: see SIGNED_OUT_ROOT.
|
||||
/** Where an active 98 title bar's gradient ends (98.css `--dialog-blue-light`). */
|
||||
const TITLE_END = '#1084d0';
|
||||
const FRAMED = 'html:not([data-wb-chat]) [data-testid="primaryColumn"]';
|
||||
const RAIL = 'header[role="banner"]';
|
||||
const NAV = `${RAIL} nav[role="navigation"]`;
|
||||
|
|
@ -44,7 +46,10 @@ export const X_PARTS: PartMap = {
|
|||
composerTool: { sel: '[data-testid="toolBar"] nav [role="button"]', text: '[data-testid="toolBar"] nav [role="button"] svg' },
|
||||
// Live 2026-10-01: the painted, bordered card is the grandparent of X's aside/section (a plain div sits
|
||||
// between), or the parent of a `*_sidebar` module (news, scores).
|
||||
sidebarCard: { sel: '[data-testid="sidebarColumn"] div:has(> div > :is(aside[role="complementary"],section[role="region"])),[data-testid="sidebarColumn"] div:has(> [data-testid$="_sidebar"])' },
|
||||
// One module per card: the column holding all the modules has a section's wrapper as a direct child
|
||||
// too, so `div:has(> div > section)` framed the whole column (live 1.0.2). Asides sit two deep,
|
||||
// sections (trends) one deep, the news/scores cards beside a `*_sidebar` tracker.
|
||||
sidebarCard: { sel: '[data-testid="sidebarColumn"] div:not(:has(> :nth-child(3))):has(> div > aside[role="complementary"]),[data-testid="sidebarColumn"] div:has(> section[role="region"]),[data-testid="sidebarColumn"] div:has(> [data-testid$="_sidebar"])' },
|
||||
menu: { sel: '#layers [role="menu"]' },
|
||||
hoverCard: { sel: '#layers [data-testid="HoverCard"]' },
|
||||
// The compose dialog's painted sheet (the child of the modal that has a composer toolbar). Never every modal: the photo
|
||||
|
|
@ -61,10 +66,10 @@ export function xDecorTargets(): DecorTargets<XSkinContext> {
|
|||
moving: `${POST},${NAV} > :is(a,button) > div,[role="tab"],[data-testid$="-follow"],[data-testid="tweetButtonInline"]`,
|
||||
pressable: `${NAV} > :is(a,button),[data-testid="tweetButtonInline"],[data-testid="tweetButton"],[data-testid$="-follow"],${POST} [role="group"] [role="button"]`,
|
||||
chrome: {
|
||||
// A window title bar on the main column, and on each sidebar card with X's own label for it.
|
||||
// A window title bar on the main column (98.css: navy fading to #1084d0, not a flat accent), and on each sidebar card with X's own label for it.
|
||||
titlebar: (title, { colors }) => [
|
||||
`${FRAMED}::before{content:${cssString(title || 'Home')};display:block;order:-1;box-sizing:border-box;height:24px;padding:4px 8px;font:700 12px/16px "Pixelated MS Sans Serif","MS Sans Serif","Tahoma",sans-serif;letter-spacing:.2px;color:#ffffff;background:linear-gradient(90deg, ${colors.inverse}, ${colors.accent});white-space:nowrap;overflow:hidden}`,
|
||||
`[data-testid="sidebarColumn"] :is(aside[role="complementary"],section[role="region"])[aria-label]::before{content:attr(aria-label);display:block;margin:-12px -16px 10px;padding:3px 8px;font:700 12px/16px "Pixelated MS Sans Serif","MS Sans Serif","Tahoma",sans-serif;color:#ffffff;background:linear-gradient(90deg, ${colors.inverse}, ${colors.accent})}`,
|
||||
`${FRAMED}::before{content:${cssString(title || 'Home')};display:block;order:-1;box-sizing:border-box;height:24px;padding:4px 8px;font:700 12px/16px "Pixelated MS Sans Serif","MS Sans Serif","Tahoma",sans-serif;letter-spacing:.2px;color:#ffffff;background:linear-gradient(90deg, ${colors.inverse}, ${TITLE_END});white-space:nowrap;overflow:hidden}`,
|
||||
`[data-testid="sidebarColumn"] :is(aside[role="complementary"],section[role="region"])[aria-label]::before{content:attr(aria-label);display:block;margin:-12px -16px 10px;padding:3px 8px;font:700 12px/16px "Pixelated MS Sans Serif","MS Sans Serif","Tahoma",sans-serif;color:#ffffff;background:linear-gradient(90deg, ${colors.inverse}, ${TITLE_END})}`,
|
||||
].join('\n'),
|
||||
// A newspaper masthead: the theme's title between two rules at the top of the column.
|
||||
masthead: (title, { colors, fonts }) => `${FRAMED}::before{content:${cssString(title || 'The Timeline')};display:block;order:-1;padding:18px 16px 12px;text-align:center;font:700 34px/1.1 ${fonts.heading};letter-spacing:-.01em;color:${colors.text};border-bottom:4px double ${colors.text};margin:0 16px}`,
|
||||
|
|
@ -152,28 +157,37 @@ ${NOT_CHAT} ${inner} > div > div:first-child{flex:1 1 auto !important}
|
|||
${NOT_CHAT} ${inner} > div > div:last-child{flex:0 0 auto !important}
|
||||
/* The same for the groups inside the row (the nav and the Post button sit in full-width wrappers). */
|
||||
${NOT_CHAT} ${inner} > div > div > div{width:auto !important;flex:0 1 auto !important;min-width:0 !important}
|
||||
${NOT_CHAT} ${NAV}{flex-direction:row !important;align-items:center !important;flex-wrap:nowrap !important;gap:2px}
|
||||
${NOT_CHAT} ${NAV}{min-width:0 !important;overflow:hidden}
|
||||
/* Items share the bar like taskbar buttons: each up to 160px, all shrinking alike, the label ending in an
|
||||
ellipsis and then only the icon (live 2026-10-02: X shows up to 12 items, more than a row of whole labels). */
|
||||
${NOT_CHAT} ${NAV} > :is(a,button){width:auto !important;flex:0 1 176px !important;min-width:36px !important;overflow:hidden}
|
||||
${NOT_CHAT} ${NAV} > :is(a,button) > div{padding:8px 8px !important;gap:0 !important;min-width:0 !important;max-width:100% !important;box-sizing:border-box;justify-content:flex-start !important}
|
||||
/* The nav's wrapper takes what is left of the row, so the items spread over the whole bar and no dead
|
||||
space sits between the last item and the account (owner, 1.0.2 at 2000px). */
|
||||
${NOT_CHAT} ${inner} > div > div:first-child > div:has(> nav[role="navigation"]){flex:1 1 0 !important}
|
||||
${edge === 'bottom' ? `/* A taskbar: Start (the logo), the quick launch (Post), then the task buttons. */
|
||||
${NOT_CHAT} ${inner} > div > div:first-child > div:has([data-testid="SideNav_NewTweet_Button"]){order:1}
|
||||
${NOT_CHAT} ${inner} > div > div:first-child > div:has(> nav[role="navigation"]){order:2}
|
||||
` : ''}${NOT_CHAT} ${NAV}{flex-direction:row !important;align-items:center !important;flex-wrap:nowrap !important;gap:2px}
|
||||
${NOT_CHAT} ${NAV}{min-width:0 !important;width:100% !important}
|
||||
/* Items are taskbar buttons. Whether they carry their labels is measured (themeBar.ts, html[data-wb-bar]):
|
||||
with labels, equal widths up to 168px and never narrower than the whole label; without, icon buttons with
|
||||
the label as a tooltip. A label is whole or absent: no ellipsis anywhere in the bar (1.0.2 "H...", "E..."). */
|
||||
${NOT_CHAT} ${NAV} > :is(a,button){position:relative;width:auto !important;flex:1 1 0 !important;max-width:168px !important;min-width:max-content !important}
|
||||
${NOT_CHAT} ${NAV} > :is(a,button) > div{padding:8px 8px !important;gap:0 !important;max-width:100% !important;box-sizing:border-box;justify-content:flex-start !important}
|
||||
${NOT_CHAT} ${NAV} > :is(a,button) > div > div:first-child{flex:none !important}
|
||||
${NOT_CHAT} ${NAV} > :is(a,button) > div > div:last-child:not(:first-child){display:block !important;flex:0 1 auto !important;margin-left:8px !important;margin-right:0 !important;padding-right:0 !important;min-width:0 !important;overflow:hidden !important;text-overflow:ellipsis !important;white-space:nowrap !important}
|
||||
${NOT_CHAT} ${NAV} > :is(a,button) > div > div:last-child:not(:first-child){display:block !important;flex:none !important;margin-left:8px !important;margin-right:0 !important;padding-right:0 !important;white-space:nowrap !important}
|
||||
${NOT_CHAT} ${NAV} > :is(a,button) > div > div:last-child:not(:first-child) span{display:inline !important;white-space:nowrap !important}
|
||||
/* Icons mode (also before the first measurement, so a label is never seen cut). */
|
||||
html:not([data-wb-chat]):not([data-wb-bar="labels"]) ${NAV}{justify-content:${edge === 'bottom' ? 'flex-start' : 'center'} !important}
|
||||
html:not([data-wb-chat]):not([data-wb-bar="labels"]) ${NAV} > :is(a,button){flex:0 0 48px !important;min-width:0 !important}
|
||||
html:not([data-wb-chat]):not([data-wb-bar="labels"]) ${NAV} > :is(a,button) > div{justify-content:center !important}
|
||||
html:not([data-wb-chat]):not([data-wb-bar="labels"]) ${NAV} > :is(a,button) > div > div:last-child:not(:first-child){display:none !important}
|
||||
html:not([data-wb-chat]):not([data-wb-bar="labels"]) ${NAV} > :is(a,button):is(:hover,:focus-visible)::after{content:attr(aria-label);position:absolute;${edge === 'bottom' ? 'bottom' : 'top'}:calc(100% + 6px);left:50%;transform:translateX(-50%);z-index:40;padding:4px 8px;white-space:nowrap;max-width:calc(100vw - 16px);font:12px/16px var(--wb-font-interface, inherit);background-color:${colors.text};color:${colors.bg};pointer-events:none}
|
||||
|
||||
${NOT_CHAT} ${RAIL} [data-testid="SideNav_NewTweet_Button"]{margin:0 0 0 8px !important;width:auto !important;min-height:40px !important;padding:0 16px !important}
|
||||
${NOT_CHAT} ${RAIL} [data-testid="SideNav_NewTweet_Button"]{margin:0 ${edge === 'bottom' ? '0 0 0' : '0 0 8px'} !important;width:auto !important;min-height:40px !important;padding:0 16px !important}
|
||||
${NOT_CHAT} ${RAIL} [data-testid="SideNav_AccountSwitcher_Button"]{margin:0 !important}
|
||||
${NOT_CHAT} main[role="main"]{padding-${edge}:56px !important;align-items:center !important}
|
||||
/* X's floating Grok and Chat buttons (bottom right) ride above a bottom bar instead of over its last items. */
|
||||
${edge === 'bottom' ? `${NOT_CHAT} :is([data-testid="chat-drawer-root"],[data-testid="GrokDrawer"]){transform:translateY(-56px)}` : ''}
|
||||
/* Popovers clear the bar: the layer guard (themeGuards.ts) keeps them inside the viewport minus this inset. */
|
||||
:root{--wb-bar-inset-${edge}:56px}
|
||||
${NOT_CHAT} ${COLUMN} > div > div:first-child{${edge === 'top' ? 'top:56px !important' : ''}}
|
||||
}
|
||||
/* Too narrow for words: the items are icon buttons (a label cut to one letter reads as noise). */
|
||||
@media (min-width:700px) and (max-width:1199px){
|
||||
${NOT_CHAT} ${NAV} > :is(a,button){flex:0 1 48px !important}
|
||||
${NOT_CHAT} ${NAV} > :is(a,button) > div{justify-content:center !important}
|
||||
/* Only a label is hidden: below 1265px X itself renders the items with their icon alone (live 2026-10-02). */
|
||||
${NOT_CHAT} ${NAV} > :is(a,button) > div > div:last-child:not(:first-child){display:none !important}
|
||||
}`;
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue