NRL Front-End
Matt Stow
Lead UX Engineer
Web
B.C.
A.D.
The News page uses 4 unique Vue apps
Multiple apps? Huh?!
- We‘re not an SPA, so we don‘t need to manage the entire application‘s state from one single source
- Unlike React, Vue has a clear distinction between what‘s an app and what‘s a component
- Each app is restricted in its scope. It only has the exact template and data that it needs
- Each page of the website can be completely different
- Our resilience to failure is much greater with everything independent
broncos: (
primary: #6c1d45,
tint: #521633,
tint-rm: #3d0d21,
secondary: #9e2b64,
highlight: #f8cc0d,
),
bulldogs: (
primary: #00468b,
tint: #00306f,
tint-rm: #001843,
secondary: #0072bc,
highlight: #0090f0,
),
cowboys: (
primary: #0c2340,
tint: #0c192f,
tint-rm: #060d1e,
secondary: #22447a,
highlight: #ffd100,
),
dragons: (
primary: #cd232c,
tint: #a6121c,
tint-rm: #1a0303,
secondary: #737373,
highlight: #dedede,
),
@mixin generate-u-themes($selector-prefix) {
@each $theme, $properties in c(themes) {
@each $property, $value in $properties {
$u-theme-selector: unquote(".#{$selector-prefix}-#{$theme}") !global;
$u-theme-variant: $property !global;
@include generate-u-theme-rules(color) {
@include u-color-properties($value, false);
}
@include generate-u-theme-rules(bg-color) {
background-color: $value;
}
@if ($property == highlight) {
@include generate-u-theme-rules(bg-color, --legible-color) {
@include u-color-properties(get-legible-color($value), false);
}
}
@include generate-u-theme-rules(border-color) {
border-color: $value;
}
}
}
}
.t-broncos .u-t-color-primary {
color: #6c1d45;
}
.t-broncos .u-t-bg-color-primary {
background-color: #6c1d45;
}
.t-broncos .u-t-border-color-primary {
border-color: #6c1d45;
}
.t-broncos .u-t-color-tint {
color: #521633;
}
.t-broncos .u-t-bg-color-tint {
background-color: #521633;
}
.t-broncos .u-t-border-color-tint {
border-color: #521633;
}
.t-broncos .u-t-color-tint-rm {
color: #3d0d21;
}
.t-broncos .u-t-bg-color-tint-rm {
background-color: #3d0d21;
}
.t-broncos .u-t-border-color-tint-rm {
border-color: #3d0d21;
}
.t-broncos .u-t-border-color-tint-rm {
border-color: #3d0d21;
}
.t-broncos .u-t-color-secondary {
color: #9e2b64;
}
.t-broncos .u-t-bg-color-secondary {
background-color: #9e2b64;
}
.t-broncos .u-t-border-color-secondary {
border-color: #9e2b64;
}
.t-broncos .u-t-color-highlight {
color: #f8cc0d;
}
.t-broncos .u-t-bg-color-highlight {
background-color: #f8cc0d;
}
.t-broncos .u-t-border-color-highlight {
border-color: #f8cc0d;
}
Match Centre
~80% smaller 💪
{
"44|2018-03-11T05:21:47Z": {
"gameSeconds": 339,
"awayTeam": {
"score": 4,
"scoring": {
"$op": "replace",
"tries": {
"made": 1,
"summaries": ["Josh Hoffman 5'"]
}
}
},
"timeline": [
[7, {
"title": "Try",
"type": "Try",
"gameSeconds": 339,
"playerId": 500256,
"teamId": 500031,
"awayScore": 4
}]
]
}
}
setupLiveStream() {
this.lastSequence = -1;
this.eventSource = new EventSource(this.liveUrl);
this.eventSource.addEventListener('message', (e) => {
if (e.lastEventId === 'close') {
this.eventSource.close();
}
else {
try {
const patchData = JSON.parse(e.data);
const eventId = e.lastEventId.split('|');
const sequence = Number(eventId[0]);
const timestamp = eventId[1];
if (timestamp > this.lastUpdated) {
if (this.lastSequence === -1 || (sequence - this.lastSequence === 1)) {
this.match = this.applyJsonPatch(patchData);
this.lastSequence = sequence;
this.match.updated = timestamp;
this.clockTimer().init();
}
else {
this.disconnectLiveStreamAndReFetch();
}
}
}
catch (error) {
this.disconnectLiveStreamAndReFetch();
}
}
});
},
Apps
import { StyleSheet } from 'react-native';
import c from '@helpers/color';
import s from '@helpers/spacing';
import t from '@helpers/theme';
export default StyleSheet.create({
'button': {
alignItems: 'center',
backgroundColor: t('secondary'),
borderColor: t('secondary'),
borderWidth: 2,
flexDirection: 'row',
borderRadius: 5,
justifyContent: 'center',
height: 50,
paddingHorizontal: s('small'),
width: '100%',
},
'button--type-hollow': {
backgroundColor: 'transparent',
},
'button.is-pressed': {
backgroundColor: t('highlight'),
borderColor: t('highlight'),
},
'button__text': {
color: c('white'),
fontSize: 14,
letterSpacing: 2,
textAlign: 'center',
width: '100%',
},
'button--on-light button__text': {
color: c('gray 222222'),
},
});
<View style={b('match-header')}>
<View
style={[
b('match-header__bg'),
u('t-bg-color-primary'),
u(`t-${props.theme.key}-bg-color-primary`)
]}
>
<Logo
style={b('match-header__bg-silhouette')}
height={300}
theme={props.theme}
variants={SILHOUETTE_VARIANTS}
width={300}
/>
</View>
</View>
Thanks
NRL Front-End Architecture
By Matt Stow
NRL Front-End Architecture
An overview of our front-end architecture across web and apps
- 1,847