From: Danilo M. Date: Tue, 21 Apr 2026 09:57:12 +0000 (+0200) Subject: fix: correct timeline layout bugs — desktop stacking, connector geometry, thumbnail... X-Git-Tag: release_22042026-1342~42 X-Git-Url: https://git.danix.xyz/?a=commitdiff_plain;h=d21d25e138f64546f1c6b2cccce0b6f943c6fc16;p=danix.xyz-2.git fix: correct timeline layout bugs — desktop stacking, connector geometry, thumbnail ratio - Remove flex from .timeline-item (was breaking abs positioning of connector/node) - Fix desktop connector math: left=calc(50%-24px)/right=calc(50%+1px), width=23px each - Fix mobile node position: left=-20px (was -27px, off-spine by ~5px) - Fix mobile connector: left=-14px/width=14px (aligned to spine right edge at 22px) - Fix thumbnail aspect-ratio: 3/2 landscape (was 2/3 portrait) - Reduce item margin-left from 44px to 36px for better mobile breathing room Co-Authored-By: Claude Haiku 4.5 --- diff --git a/themes/danix-xyz-hacker/assets/css/main.css b/themes/danix-xyz-hacker/assets/css/main.css index 89c3fda..829cbcb 100644 --- a/themes/danix-xyz-hacker/assets/css/main.css +++ b/themes/danix-xyz-hacker/assets/css/main.css @@ -513,10 +513,11 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] { @apply relative mx-auto max-w-5xl px-4 py-12; } - /* Vertical spine — center on desktop, left on mobile */ + /* Vertical spine */ .timeline::before { content: ''; @apply absolute top-0 bottom-0; + /* Mobile: fixed 20px from container left edge */ left: 20px; width: 2px; background: linear-gradient(to bottom, var(--accent), var(--accent2, var(--accent))); @@ -530,18 +531,16 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] { } } - /* Each timeline row */ + /* Each timeline row — block, full width, positioned context for abs children */ .timeline-item { @apply relative mb-10; - /* Mobile: offset right of left spine */ - margin-left: 44px; + /* Mobile: push card right of the left spine (spine 20px + 2px + gap 8px = 30px; use 36px for breathing room) */ + margin-left: 36px; } @screen md { .timeline-item { margin-left: 0; - @apply flex items-start; - /* Each item takes full width; card is positioned via padding inside */ } } @@ -550,21 +549,25 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] { @apply absolute; top: 20px; height: 2px; - /* Mobile: from spine (left:22px) to card left edge (left:44px) */ - left: -22px; - width: 22px; + /* Mobile: spine right edge at 22px, item left at 36px → offset = -14px, width = 14px */ + left: -14px; + width: 14px; } @screen md { - /* Desktop: driven by .timeline-item--left / --right modifier */ + /* + spine center = 50% of item. Spine is 2px: left edge at 50%-1px, right at 50%+1px. + Cards occupy [0 .. 50%-24px] (left) or [50%+24px .. 100%] (right). + Left connector: left=50%-24px, width=23px → touches card right edge and spine left. + Right connector: left=50%+1px, width=23px → touches spine right and card left. + */ .timeline-item--left .timeline-connector { - right: calc(50% - 28px + 1px); - left: auto; - width: 28px; + left: calc(50% - 24px); + width: 23px; } .timeline-item--right .timeline-connector { - left: calc(50% + 28px - 28px); - width: 28px; + left: calc(50% + 1px); + width: 23px; } } @@ -572,8 +575,8 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] { .timeline-node { @apply absolute rounded-full z-10; top: 14px; - /* Mobile: on left spine at left:20px, node is 10px → left:15px */ - left: -27px; + /* Mobile: spine center = 21px, item left = 36px → node left = 21-5-36 = -20px */ + left: -20px; width: 10px; height: 10px; border: 2px solid var(--bg); @@ -584,13 +587,7 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] { width: 12px; height: 12px; top: 14px; - left: calc(50% - 6px); - /* Override mobile left positioning */ - transform: none; - } - /* Reset mobile left for desktop — node always on center spine */ - .timeline-item--left .timeline-node, - .timeline-item--right .timeline-node { + /* Desktop: spine center = 50% of item. Node center on spine: left = 50% - 6px */ left: calc(50% - 6px); } } @@ -598,6 +595,9 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] { /* ---- Card wrapper ---- */ .timeline-card { @apply flex border rounded-lg overflow-hidden bg-surface; + /* Mobile: column (thumb on top) */ + flex-direction: column; + width: 100%; transition: box-shadow 0.2s, transform 0.2s; } @@ -605,34 +605,38 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] { transform: translateY(-2px); } - /* Mobile: full width */ - .timeline-card { - width: 100%; - } - @screen md { - /* Desktop: card occupies ~45% width, positioned by padding on .timeline-item */ + /* Desktop: push card into left or right half via item padding */ .timeline-item--left { - padding-right: calc(50% + 28px); + padding-right: calc(50% + 24px); } .timeline-item--right { - padding-left: calc(50% + 28px); + padding-left: calc(50% + 24px); + } + /* Left card: thumb outer-left, body inner-right */ + .timeline-item--left .timeline-card { + flex-direction: row; + } + /* Right card: body inner-left, thumb outer-right */ + .timeline-item--right .timeline-card { + flex-direction: row-reverse; } } /* ---- Thumbnail panel ---- */ .timeline-thumb { @apply flex-shrink-0 overflow-hidden; - /* Mobile: full width banner on top — handled by flex-direction:column on mobile card */ + /* Mobile: full-width banner */ width: 100%; height: 90px; } @screen md { .timeline-thumb { - width: 38%; + /* 3:2 landscape: wider than tall */ + width: 40%; height: auto; - aspect-ratio: 2 / 3; + aspect-ratio: 3 / 2; } } @@ -650,25 +654,6 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] { @apply flex flex-col gap-2 p-4 flex-1; } - /* Mobile card stacks thumbnail above body */ - .timeline-card { - flex-direction: column; - } - - @screen md { - .timeline-card { - flex-direction: row; - } - /* Left card: thumb first (outer=left), body second */ - .timeline-item--left .timeline-card { - flex-direction: row; - } - /* Right card: body first (inner=left), thumb last (outer=right) */ - .timeline-item--right .timeline-card { - flex-direction: row-reverse; - } - } - /* ---- Meta row (TYPE · date) ---- */ .timeline-meta { @apply flex items-center gap-2 text-xs font-mono tracking-widest uppercase; diff --git a/themes/danix-xyz-hacker/assets/css/main.min.css b/themes/danix-xyz-hacker/assets/css/main.min.css index a64fb66..c330e5f 100644 --- a/themes/danix-xyz-hacker/assets/css/main.min.css +++ b/themes/danix-xyz-hacker/assets/css/main.min.css @@ -1548,13 +1548,14 @@ button, padding-bottom: 3rem; } -/* Vertical spine — center on desktop, left on mobile */ +/* Vertical spine */ .timeline::before { content: ''; position: absolute; top: 0px; bottom: 0px; + /* Mobile: fixed 20px from container left edge */ left: 20px; width: 2px; background: linear-gradient(to bottom, var(--accent), var(--accent2, var(--accent))); @@ -1568,21 +1569,18 @@ button, } } -/* Each timeline row */ +/* Each timeline row — block, full width, positioned context for abs children */ .timeline-item { position: relative; margin-bottom: 2.5rem; - /* Mobile: offset right of left spine */ - margin-left: 44px; + /* Mobile: push card right of the left spine (spine 20px + 2px + gap 8px = 30px; use 36px for breathing room) */ + margin-left: 36px; } @media (min-width: 768px) { .timeline-item { margin-left: 0; - display: flex; - align-items: flex-start; - /* Each item takes full width; card is positioned via padding inside */ } } @@ -1592,23 +1590,27 @@ button, position: absolute; top: 20px; height: 2px; - /* Mobile: from spine (left:22px) to card left edge (left:44px) */ - left: -22px; - width: 22px; + /* Mobile: spine right edge at 22px, item left at 36px → offset = -14px, width = 14px */ + left: -14px; + width: 14px; } @media (min-width: 768px) { - /* Desktop: driven by .timeline-item--left / --right modifier */ + /* + spine center = 50% of item. Spine is 2px: left edge at 50%-1px, right at 50%+1px. + Cards occupy [0 .. 50%-24px] (left) or [50%+24px .. 100%] (right). + Left connector: left=50%-24px, width=23px → touches card right edge and spine left. + Right connector: left=50%+1px, width=23px → touches spine right and card left. + */ .timeline-item--left .timeline-connector { - right: calc(50% - 28px + 1px); - left: auto; - width: 28px; + left: calc(50% - 24px); + width: 23px; } .timeline-item--right .timeline-connector { - left: calc(50% + 28px - 28px); - width: 28px; + left: calc(50% + 1px); + width: 23px; } } @@ -1619,8 +1621,8 @@ button, z-index: 10; border-radius: 9999px; top: 14px; - /* Mobile: on left spine at left:20px, node is 10px → left:15px */ - left: -27px; + /* Mobile: spine center = 21px, item left = 36px → node left = 21-5-36 = -20px */ + left: -20px; width: 10px; height: 10px; border: 2px solid var(--bg); @@ -1631,15 +1633,7 @@ button, width: 12px; height: 12px; top: 14px; - left: calc(50% - 6px); - /* Override mobile left positioning */ - transform: none; - } - - /* Reset mobile left for desktop — node always on center spine */ - - .timeline-item--left .timeline-node, - .timeline-item--right .timeline-node { + /* Desktop: spine center = 50% of item. Node center on spine: left = 50% - 6px */ left: calc(50% - 6px); } } @@ -1670,6 +1664,9 @@ article.border.border-border\/30.rounded-lg.timeline-card.group.bg-bg { } .timeline-card { + /* Mobile: column (thumb on top) */ + flex-direction: column; + width: 100%; transition: box-shadow 0.2s, transform 0.2s; } @@ -1677,10 +1674,28 @@ article.border.border-border\/30.rounded-lg.timeline-card.group.bg-bg { transform: translateY(-2px); } -/* Mobile: full width */ +@media (min-width: 768px) { + /* Desktop: push card into left or right half via item padding */ -.timeline-card { - width: 100%; + .timeline-item--left { + padding-right: calc(50% + 24px); + } + + .timeline-item--right { + padding-left: calc(50% + 24px); + } + + /* Left card: thumb outer-left, body inner-right */ + + .timeline-item--left .timeline-card { + flex-direction: row; + } + + /* Right card: body inner-left, thumb outer-right */ + + .timeline-item--right .timeline-card { + flex-direction: row-reverse; + } } /* ---- Thumbnail panel ---- */ @@ -1696,16 +1711,17 @@ article.border.border-border\/30.rounded-lg.timeline-thumb.group.bg-bg { } .timeline-thumb { - /* Mobile: full width banner on top — handled by flex-direction:column on mobile card */ + /* Mobile: full-width banner */ width: 100%; height: 90px; } @media (min-width: 768px) { .timeline-thumb { - width: 38%; + /* 3:2 landscape: wider than tall */ + width: 40%; height: auto; - aspect-ratio: 2 / 3; + aspect-ratio: 3 / 2; } } @@ -1731,30 +1747,6 @@ article.border.border-border\/30.rounded-lg.timeline-thumb.group.bg-bg { padding: 1rem; } -/* Mobile card stacks thumbnail above body */ - -.timeline-card { - flex-direction: column; -} - -@media (min-width: 768px) { - .timeline-card { - flex-direction: row; - } - - /* Left card: thumb first (outer=left), body second */ - - .timeline-item--left .timeline-card { - flex-direction: row; - } - - /* Right card: body first (inner=left), thumb last (outer=right) */ - - .timeline-item--right .timeline-card { - flex-direction: row-reverse; - } -} - /* ---- Meta row (TYPE · date) ---- */ .timeline-meta {