Legacy audit
Widgets ported before the parity process, and whether to reuse, rework or discard each.
Audit of widgets ported before the parity process. All are migrated_unverified. Machine-readable copy: legacy-audit.json.
- Legacy root:
telstra-legacy-aflm-web(paths below are relative to it). - Set A:
packages/ui/srconmain. Set B:packages/ui/srconorigin/legacy-poc. - Live reference:
_migration-analysis/page-catalogue/pages/news-article-taylor-walker-retire.html. - Breakpoints in the live CSS: 640 / 840 / 1025 / 1300 (max-width) and 641 / 841 / 1026 / 1301 (min-width), plus a 1159/1160 nav breakpoint and 1352/1400 in the telstra-bar menus.
tailwind-preset.cssdefinesphablet/tablet/desktop/desktop-nav/wideat the min-width values, and still has Tailwind's defaultsm/md/lg. - Theming: competition themes (AFLM, AFLW, Gather Round, Finals) swap the
--fill-*,--text-*,--button-*and--tag-content-*tokens (src/styles/includes/settings/_colour-tokens.scss, overridden insrc/widgets/sites/aflm/misc/theme-switcher.ftl).t-dark/t-lightonly appear in the filters, full-page-parallax and photo-gallery-feature-embed SCSS. Article widgets use--dark-mode/--light-mode/--dark-textmodifiers instead.
Verdicts
reuse means it should pass parity with small fixes. rework means keep the structure and rebuild the styles and variants. discard means rebuild from the legacy source.
| Port | Set | Path | Claims to port | Mapping right? | Verdict |
|---|---|---|---|---|---|
| article-list | A | article-list/article-list.tsx | nothing | Nearest is article-list/* via includes/components/media-listing.ftl | discard |
| global-footer | A | global-footer/global-footer.tsx | nothing | The article page uses footer-menu/footer-menu.ftl and telstra-footer/telstra-footer.ftl. The global-footer/footer.ftl shell isn't on the page | discard |
| image | A | image/image.tsx | nothing | photo/photo.ftl, photo-no-caption.ftl | rework |
| navigation | A | navigation/navigation-menu.tsx | nothing | main-navigation/includes/_menu-list.ftl | rework (keep menusOf) |
| promo | A | promo/promo.tsx | nothing | Legacy promo has 10 variants plus 6 sidebar promos, and this matches none of them | discard |
| rich-text | A | rich-text/rich-text.tsx | nothing | article/standard.ftl article body | rework |
| site-header | A | site-header/site-header.tsx | nothing | Mixes telstra-bar and main-navigation together | discard |
| section / row / column | A | layout/* | nothing | templates/article-standard.html regions, layout/_grids.scss, _widget.scss | rework |
| club-menu | B | club-menu.tsx | telstra-bar/club-menu-v3.ftl, includes/components/club-list.ftl | Yes. The toggle JS is main-navigation/js/navigation-drop-down.js | rework |
| media-carousel | B | media-carousel.tsx | mixed-content/slider.ftl, common/slider/slider.js | Yes | rework |
| media-thumbnail | B | media-thumbnail.tsx | includes/components/media-thumbnail.ftl | Yes | rework |
| promo-list | B | promo-list.tsx | promo-list/includes/_promo-listing.ftl | Yes | rework |
| promo-side-by-side | B | promo-side-by-side.tsx | promo/includes/_side-by-side-promo.ftl, promo/side-by-side.ftl | Yes | reuse |
| promo-side-by-side-list | B | promo-side-by-side-list.tsx | promo/side-by-side-list.ftl | Yes | reuse |
| scoreboard-badge | B | scoreboard-badge.tsx | nothing | No legacy source | discard |
| telstra-bar | B | telstra-bar.tsx | telstra-bar/telstra-bar-v3.ftl, -aflw.ftl | Yes | rework |
| telstra-dropdown | B | telstra-dropdown.tsx | includes/components/telstra-dropdown-v3.ftl | Yes (the widget file is telstra-bar/telstra-dropdown-v3.ftl) | rework |
| widget-header | B | widget-header.tsx | includes/components/widget-header.ftl | Yes | rework |
| article-widget-placeholder | B | article-widget-placeholder.tsx | Says it is a placeholder | n/a | discard |
| shadcn button | B (same file on main) | components/ui/button.tsx | nothing | styles/includes/components/_button.scss | rework |
| shadcn carousel | B | components/ui/carousel.tsx | slider.js tracking events | Partly | rework |
Cross-cutting gaps:
- Set B uses a different interface from main. B components take props and use
blockContainer(meta, isEditable). Main expectsBlockProps<T>with a.schema.ts, and itsblockContainer(edit)takes one argument. - B has no fixtures. Only story args exist.
- Carousel dependencies are missing on main.
embla-carousel-reactandlucide-reactare not installed. - Set A ports are generic placeholders. They use shadcn/Tailwind defaults with no legacy BEM, use
sm/md/lgbreakpoints, and have inventedstylevariants.
Gaps per port
| Port | Markup / BEM | Variants | Breakpoints | Theming | Behaviour | Data | Tests / stories / fixtures |
|---|---|---|---|---|---|---|---|
| A article-list | Generic card grid with no media-list or media-thumbnail__* structure | No sidebar-regular, sidebar-featured, row-card-phablet or large-thumbnail variants. No widget-header--sidebar. No widget-footer view-more, load-more or <ol> | sm/lg instead of block-list-4 / -3-tablet / -1-phablet | shadcn card/border | No trackCardClicks | No type, duration, publish label, competition reference, tag, sponsor, or premium/geo flags | test, story. No content fixture |
| A global-footer | No partners strip, app/social rows, back-to-top, afl-logo-sponsor sprite or Telstra footer | Invented default/dark/minimal | sm/lg, max-w-7xl | partial | No nav/partner tracking | Acknowledgement is rich text here, an i18n label in legacy | test, story, fixture |
| A image | No photo__* BEM or camera caption icon | No photo--portrait | No responsive srcset | none | No floating embeddable behaviour | Caption should fall back to photo.description | test, story, fixture |
| A navigation | Generic <nav><ul> | n/a | n/a | none | Active state is an exact href match, not get-active-node.ftl | menusOf is reusable | test, fixture. No story |
| A promo | Generic card | No variants | none | Inline backgroundColor | No #VideoModal activator (Brightcove_ID) | n/a | test, story, fixture |
| A rich-text | Paragraph and heading text only | No links, lists, tables or embeds | n/a | Not _article-body.scss | No article-body.js | n/a | test, story, fixture |
| A site-header | No mega-menu, dynamic-more, drawer, search, AFLID, regional display, secondary nav or social | Invented styles and logoDark | md (768) instead of 1159/1160 | Invented CTA | <details> instead of the dropdown state machine | n/a | test, story, fixture |
| A layout | max-w-7xl instead of .wrapper | No main/sidebar/sticky-sidebar/bottom regions | n/a | Dark is bg-fill-900. Legacy widget--dark-mode uses --fill-bg-feature | n/a | Gap/span settings are invented | tests, story, fixtures |
| B club-menu | clubs-menu-v3__* and club-list__* not reproduced | n/a | No 1352/1400 rules | ok (fixed tokens) | Port of useDropdown is ok | Takes ReactNode icons. Legacy reads content.additionalCssClasses sprite and getActiveClass | test, story |
| B media-carousel | No slider__* markup or js-paginator | No widget--mc or removeMobileBorderTop | Slide widths not traced to _slider.scss | n/a | Embla instead of slider.js (documented). No betting/18+ gating | ok | test, story |
| B media-thumbnail | Title is h3 (legacy uses h2). Adds a "Premium" badge legacy doesn't have. Emoji instead of gather-round-flag/trophy sprites. No comp logo, type icon, chevron or content-label-edge | No modifier support at all: sidebar-regular (applies at ≥1026 and ≤640), sidebar-featured, row-card(-phablet), feature-card, hero-card, wide-card, video-player, skeleton, --has-footer, --has-publish-label, --{label}, --premium, --trailer | 640/840/1025/1300 not implemented | Fixed tokens. No dark feature-card | No modal activator (#VideoModal/#GalleryModal with data-ui-args). No trailer player. No lazy srcset | data-tag-geo-blocked should hold the region string | test, 8 stories |
| B promo-list | Close | Missing bgImage (Large), --image-only, --parallax, widget-header--light-mode | Column counts wrong for every size (see JSON) | Dark mode uses bg-theme-primary. Legacy uses --fill-bg-feature | No click tracking or betting gating | Matches playlist.playlistItems | test, 6 stories |
| B promo-side-by-side(-list) | Tailwind instead of promo-sbs__* BEM, no .wrapper | image-right alternation is correct | 841 is correct | ok | No #VideoModal activator | CTA should need linkText | tests, stories |
| B telstra-bar | telstra-bar-v3__* BEM not reproduced | AFL/AFLW handled | tablet is 840 (min) in legacy, 841 in the port | --fill-nav-secondary is correct | Tracking callback is ok | Takes ReactNode icons instead of content.additionalCss sprite + -white. Missing aflPlayUrl customProperties | test, stories |
| B telstra-dropdown | Header background image missing | n/a | No 1352 rule | n/a | Focus trap and Escape are ok | Icons should come from additionalCssClasses | test, stories |
| B widget-header | Arrow is a text glyph. Legacy uses the arrow-right sprite, or telstra-external plus _blank for external links | Missing --sidebar, --smaller-text, --has-sponsor (+ sponsor slot), --light-mode | No 2.8rem title ≤840 or 2.2rem ≤640 | Arrow fill should be --fill-accent-secondary | n/a | Missing headingTag, backupTitle, cssClass and nested slot | test, 5 stories |
Article page widgets
Source page: afl.com.au/news/<id>/<slug>. Every legacy path below exists.
| # | id | Type | Region | Legacy source (primary) | Prior port | Theme | Modes | Data |
|---|---|---|---|---|---|---|---|---|
| 1 | telstra-bar | chrome | header | telstra-bar/telstra-bar-v3.ftl, _telstra-bar-v3.scss, js/telstra-bar.js | B telstra-bar, rework | yes | light | cms (menu.children, customProperties) |
| 2 | telstra-bar-club-menu | chrome | header | telstra-bar/club-menu-v3.ftl, includes/components/club-list.ftl | B club-menu, rework | yes | light | cms |
| 3 | telstra-bar-dropdown | chrome | header | telstra-bar/telstra-dropdown-v3.ftl, includes/components/telstra-dropdown-v3.ftl | B telstra-dropdown, rework | no | light | cms |
| 4 | main-navigation | chrome | header | main-navigation/main-navigation-bar.ftl, includes/_menu-list.ftl, js/navigation.js, js/navigation-drop-down.js | A site-header, discard | yes | light | cms |
| 5 | main-navigation-dynamic-more | behaviour | header | main-navigation/js/dynamic-more.js, templates/dynamic-more.html | none | yes | light | static |
| 6 | aflid-user | chrome | header | aflid-user/aflid-user.ftl, js/aflid-user.js, templates/*.html | none | yes | light | api: Okta authClient |
| 7 | main-menu-regional-display | behaviour | header | main-navigation/js/providers/MainMenuRegionalDisplayProvider.jsx (.js-regional-display) | none | yes | light | static (local site settings) |
| 8 | advert-leaderboard | element | header | advert/leaderboard-v2.ftl, advert/js/providers/AdvertisementProvider.jsx | none | no | light | api: GPT (window.ReactGPTAds) |
| 9 | article-header | page-section | main | article/includes/_article-header.ftl, _article-author.ftl (called from article/standard.ftl) | none | yes | light | cms |
| 10 | article-author-photo | behaviour | main | article/js/article-author-photo.js | none | no | light | api: {aflApi}content/{account}/bio/en/{authorId} |
| 11 | article-age-tag | behaviour | main | article/js/article-age-tag.js | none | no | light | static |
| 12 | bio-tracking | behaviour | main | Not found in the legacy repo or the cached HTML | none | no | light | unknown |
| 13 | article-body | page-section | main | article/standard.ftl (not static.ftl), _article-body.scss, js/article-body.js | A rich-text, rework | yes | light | cms |
| 14 | article-video-player | element | main | includes/components/inline-player.ftl, includes/macros/feature-video.ftl, common/video/video.js | B placeholder, discard | yes | light | cms + Brightcove |
| 15 | skip-to-content | behaviour | main | includes/macros/feature-video.ftl, embeddable/js/skip-to-content.js | none | no | light | static |
| 16 | social-share-page | shared-block | main | includes/components/social-share.ftl, social-share/share-page.js, common/social/page-share.js | none | yes | light | static |
| 17 | advert-sticky-banner | element | overlay | advert/sticky-banner-v2.ftl, advert/js/close-ad.js | none | no | light | api: GPT |
| 18 | advert-mrec-sidebar | element | sidebar | advert/mrec-v2.ftl | none | no | light | api: GPT |
| 19 | article-list-sidebar-must-watch | element | sidebar | article-list/article-list-must-watch.ftl + widget-header--sidebar + media-thumbnail--sidebar-regular | A article-list, discard (build on B media-thumbnail + widget-header) | yes | light | cms |
| 20 | article-list-sidebar-next-up | element | sidebar | article-list/article-list-sidebar.ftl (same markup) | A article-list, discard | yes | light | cms |
| 21 | video-sidebar-featured | element | sidebar | video/featured-video.ftl. In the cached page it renders from article/featured-article.ftl (single-video__featured media-thumbnail--sidebar-featured) | B media-thumbnail, rework | yes | light | cms |
| 22 | advert-mrec-sticky-sidebar | element | sidebar | advert/mrec-sticky-v2.ftl | none | no | light | api: GPT |
| 23 | parallax-content-up-next | element | main | article/up-next.ftl, includes/components/parallax-content.ftl, common/content/parallax-content.js | none | yes | light, dark | cms (relatedContent / publishedBefore / publishedAfter) |
| 24 | article-list-full-width-video | element | main | video-list/video-list-grid.ftl via media-listing.ftl (default thumbnail) | A article-list, discard | yes | light | cms |
| 25 | article-list-row-card-phablet | element | main | article-list/article-list-4-per-row.ftl (media-thumbnail--row-card-phablet) | A article-list, discard | yes | light | cms |
| 26 | footer-menu | chrome | footer | footer-menu/footer-menu.ftl, partners.ftl, appstore.ftl, js/footer-menu.js | A global-footer, discard | yes | light | cms |
| 27 | scroll-to-top | behaviour | footer | footer-menu/js/scroll-to-top.js | none | yes | light | static |
| 28 | telstra-footer | chrome | footer | telstra-footer/telstra-footer.ftl | A global-footer, discard | no | light | cms |
| 29 | page-notifications | behaviour | overlay | Not found in the legacy repo or the cached HTML | none | no | light | unknown |
| 30 | adhoc-event-notifications | behaviour | overlay | notifications/adhoc-event-notifications.ftl, js/adhoc-notification.js, js/adhoc-modal.js | none | no | light | api: {aflApi}broadcasting/afl/live/{video|audio} (polled) |
| 31 | trade-radio-mini-popup | behaviour | overlay | trade-radio/trade-radio-mini-popup.ftl, js/TradeRadioMiniPopupProvider.jsx, js/TradeRadioLoader.jsx | none | yes | light | api: {aflApi}broadcasting/events, plus a content item for the image |
| 32 | site-settings-modal | behaviour | overlay | common/react/components/site-settings-modal/**, mounted from templates/general.html (.js-site-settings) | none | yes | light | api: Okta isAuthenticated, Salesforce marketing prefs, {aflApi}content |
| 33 | gallery-modal | behaviour | overlay | modal/modal.ftl, common/modal/gallery-modal.js, common/modal/constructor.js | none | yes | light | api: {aflApi}content/{account}/playlist/en/{id} |
| 34 | video-modal | behaviour | overlay | video-modal/video-modal.ftl, js/video-modal-widget.js, common/video/video-modal.js | none | yes | light | api: {aflApi}content/{account}/video/en/{id} (+ promo for sponsors) |
| 35 | upsell-modal | behaviour | overlay | upsell-modal/upsell-modal.ftl, js/upsell-modal.js | none | yes | light | api: content/.../video/en/{id}, then content/.../promo/en/{promoId} |
Corrections to the brief and to page-catalogue/results.json, checked against the live HTML:
- The article body comes from
article/standard.ftl, notarticle/static.ftl. In the live HTML,article__bodyhasdata-script="aflm_article"and comes right after@articleHeader. Neither is true ofstatic.ftl. - close-ad and the leaderboard/MRECs are the
-v2React-ad FTLs. The live markup contains.js-advert-2, which only the-v2files emit. - The full-width default-thumbnail list ("Latest Videos") is a video-list FTL. Its
data-widget="article-list"comes from the sharedmedia-listing.ftl, not from thearticle-list/folder. - The featured sidebar video in the cached page is
article/featured-article.ftl.video/featured-video.ftlemitsdata-widget="video", which does not appear in either cached article. page-notificationsandbio-trackingdon't exist anywhere in this repo. Confirm on the live page whether they are injected by the platform before scoping them.