Skip to content
GitLab
Menu
Why GitLab
Pricing
Contact Sales
Explore
Why GitLab
Pricing
Contact Sales
Explore
Sign in
Get free trial
Commits on Source (2)
Analytics components refactor and summary tab
· becf346e
Olivia Madrid
authored
Nov 11, 2019
and
Mark Harding
committed
Nov 11, 2019
becf346e
Merge branch 'generic-layout-2194' into 'master'
· 321308e7
Mark Harding
authored
Nov 11, 2019
Analytics components refactor and summary tab See merge request
!634
321308e7
Expand all
Hide whitespace changes
Inline
Side-by-side
src/app/common/common.module.ts
View file @
321308e7
...
...
@@ -115,7 +115,14 @@ import { ToggleComponent } from './components/toggle/toggle.component';
import
{
MarketingAsFeaturedInComponent
}
from
'
./components/marketing/as-featured-in.component
'
;
import
{
SidebarMenuComponent
}
from
'
./components/sidebar-menu/sidebar-menu.component
'
;
import
{
ChartV2Component
}
from
'
./components/chart-v2/chart-v2.component
'
;
import
{
MiniChartComponent
}
from
'
./components/mini-chart/mini-chart.component
'
;
import
*
as
PlotlyJS
from
'
plotly.js/dist/plotly.js
'
;
import
{
PlotlyModule
}
from
'
angular-plotly.js
'
;
import
{
PageLayoutComponent
}
from
'
./components/page-layout/page-layout.component
'
;
import
{
DashboardLayoutComponent
}
from
'
./components/dashboard-layout/dashboard-layout.component
'
;
import
{
ShadowboxLayoutComponent
}
from
'
./components/shadowbox-layout/shadowbox-layout.component
'
;
import
{
ShadowboxHeaderComponent
}
from
'
./components/shadowbox-header/shadowbox-header.component
'
;
PlotlyModule
.
plotlyjs
=
PlotlyJS
;
@
NgModule
({
imports
:
[
...
...
@@ -124,6 +131,7 @@ import { MiniChartComponent } from './components/mini-chart/mini-chart.component
RouterModule
,
FormsModule
,
ReactiveFormsModule
,
PlotlyModule
,
],
declarations
:
[
MINDS_PIPES
,
...
...
@@ -220,7 +228,10 @@ import { MiniChartComponent } from './components/mini-chart/mini-chart.component
MarketingAsFeaturedInComponent
,
SidebarMenuComponent
,
ChartV2Component
,
MiniChartComponent
,
PageLayoutComponent
,
DashboardLayoutComponent
,
ShadowboxLayoutComponent
,
ShadowboxHeaderComponent
,
],
exports
:
[
MINDS_PIPES
,
...
...
@@ -312,6 +323,10 @@ import { MiniChartComponent } from './components/mini-chart/mini-chart.component
MarketingComponent
,
MarketingAsFeaturedInComponent
,
SidebarMenuComponent
,
ChartV2Component
,
PageLayoutComponent
,
DashboardLayoutComponent
,
ShadowboxLayoutComponent
,
],
providers
:
[
SiteService
,
...
...
src/app/
modules/analytics/
v2/chart-palette.default.ts
→
src/app/
common/components/chart-
v2/chart-palette.default.ts
View file @
321308e7
File moved
src/app/common/components/chart-v2/chart-v2.component.html
View file @
321308e7
<!--
<div
<div
#chartContainer
class=
"m-chartV2__chartContainer"
[ngClass]="{ isTouchDevice: isTouchDevice }"
[ngClass]=
"{ isTouchDevice: isTouchDevice
, isMini: isMini
}"
>
<plotly-plot
*ngIf=
"init"
#graphDiv
id="graphDiv"
[data]=
"data"
[layout]=
"layout"
[config]=
"config"
...
...
@@ -14,48 +12,70 @@
[style]=
"{ position: 'relative' }"
(hover)=
"onHover($event)"
(unhover)=
"onUnhover($event)"
(plotly_click)="onClick($event)
"
id=
"graphDiv
"
>
</plotly-plot>
</div>
<div #hoverInfoDiv id="hoverInfoDiv" class="m-chartV2__hoverInfoDiv">
<i *ngIf="isTouchDevice" class="material-icons" (click)="onUnhover($event)"
<div
#hoverInfoDiv
class=
"m-chartV2__hoverInfoDiv"
>
<i
*ngIf=
"isTouchDevice"
class=
"material-icons m-chartV2__hoverInfo__closeBtn"
(click)=
"onUnhover($event)"
>
close
</i
>
<div class="m-chartV2__hoverInfo__row">
{{ hoverInfo.date | utcDate | date: datePipe }}
</div>
<div
[ngSwitch]="selectedMetric?.unit"
class="m-chartV2__hoverInfo__row--primary"
>
<ng-template ngSwitchCase="number">
{{ hoverInfo.value | number }} {{ selectedMetric.label | lowercase }}
</ng-template>
<ng-template ngSwitchCase="usd">
{{ hoverInfo.value | currency }} USD
</ng-template>
<ng-template ngSwitchDefault>
{{ hoverInfo.value | number: '1.1-3' }} {{ selectedMetric?.unit }}
</ng-template>
</div>
<div class="m-chartV2__hoverInfo__row" *ngIf="isComparison">
vs
<ng-container
[ngSwitch]="selectedMetric?.unit"
class="m-chartV2__hoverInfo__row"
>
<ng-template ngSwitchCase="number">
{{ hoverInfo.comparisonValue | number }}
</ng-template>
<ng-template ngSwitchCase="usd">
{{ hoverInfo.comparisonValue | currency }}
</ng-template>
<ng-template ngSwitchDefault>
{{ hoverInfo.comparisonValue | number: '1.1-3' }}
</ng-template>
</ng-container>
on {{ hoverInfo.comparisonDate | utcDate | date: datePipe }}
<div
class=
"m-chartV2__hoverInfo__wrapper"
>
<div
class=
"m-chartV2__hoverInfo__arrowContainer"
*ngIf=
"isMini"
>
<i
class=
"material-icons"
>
arrow_upward
</i>
</div>
<div
class=
"m-chartV2__hoverInfo__rowsContainer"
>
<div
class=
"m-chartV2__hoverInfo__row"
>
{{ hoverInfo.date | utcDate | date: datePipe }}
</div>
<div
[ngSwitch]=
"rawData?.unit"
class=
"m-chartV2__hoverInfo__row--primary"
>
<ng-template
ngSwitchCase=
"number"
>
{{ hoverInfo.value | number: '1.0-0' | abbr }}
{{ rawData.label | lowercase }}
</ng-template>
<ng-template
ngSwitchCase=
"usd"
>
{{ hoverInfo.value | currency }} USD
</ng-template>
<ng-template
ngSwitchCase=
"eth"
>
{{ hoverInfo.value | number: '1.3-3' }} ETH
</ng-template>
<ng-template
ngSwitchCase=
"tokens"
>
{{ hoverInfo.value | number: '1.1-3' }} Tokens
</ng-template>
<ng-template
ngSwitchDefault
>
{{ hoverInfo.value | number: '1.0-3' }} {{ rawData?.unit }}
</ng-template>
</div>
<div
class=
"m-chartV2__hoverInfo__row"
*ngIf=
"isComparison"
>
vs
<ng-container
[ngSwitch]=
"rawData?.unit"
class=
"m-chartV2__hoverInfo__row"
>
<ng-template
ngSwitchCase=
"number"
>
{{ hoverInfo.comparisonValue | number: '1.0-0' | abbr }}
</ng-template>
<ng-template
ngSwitchCase=
"usd"
>
{{ hoverInfo.comparisonValue | currency }}
</ng-template>
<ng-template
ngSwitchCase=
"eth"
>
{{ hoverInfo.value | number: '1.3-3' }} ETH
</ng-template>
<ng-template
ngSwitchCase=
"tokens"
>
{{ hoverInfo.value | number: '1.1-3' }} Tokens
</ng-template>
<ng-template
ngSwitchDefault
>
{{ hoverInfo.comparisonValue | number: '1.1-3' }}
</ng-template>
</ng-container>
on {{ hoverInfo.comparisonDate | utcDate | date: datePipe }}
</div>
</div>
</div>
</div>
-->
</div>
src/app/common/components/chart-v2/chart-v2.component.scss
View file @
321308e7
m-chartV2
{
display
:
block
;
position
:
relative
;
margin-left
:
40px
;
}
.js-plotly-plot
,
.plot-container
{
height
:
44vh
;
min-height
:
44vh
;
display
:
block
;
}
#graphDiv
{
display
:
block
;
position
:
relative
;
g
,
g
>
*
{
cursor
:
default
;
}
>
*
{
transition
:
background-color
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
)
,
color
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
}
.main-svg
{
max-width
:
100%
;
}
}
.m-chartV2__hoverInfoDiv
{
width
:
160px
;
padding
:
12px
;
position
:
absolute
;
pointer-events
:
none
;
border-radius
:
3px
;
font-size
:
12px
;
z-index
:
9999999999
;
opacity
:
0
;
transition
:
opacity
0
.2s
ease-in
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
box-shadow
:
0
0
4px
rgba
(
themed
(
$m-black
)
,
0
.3
);
color
:
themed
(
$m-grey-300
);
}
[
class
*=
'm-chartV2__hoverInfo__row'
]
{
padding-bottom
:
4px
;
font-weight
:
300
;
&
:last-of-type
{
padding-top
:
2px
;
}
}
.m-chartV2__hoverInfo__row--primary
{
font-weight
:
400
;
font-size
:
15px
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-600
);
}
}
.m-chartV2__hoverInfo__closeBtn
{
display
:
none
;
font-size
:
15px
;
position
:
absolute
;
cursor
:
pointer
;
top
:
10px
;
right
:
10px
;
transition
:
color
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
&
:active
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-500
);
}
}
}
}
// ----------------------------------------------------
.isTouchDevice
.m-chartV2__hoverInfoDiv
.m-chartV2__hoverInfo__closeBtn
{
display
:
block
;
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
m-chartV2
{
margin-left
:
16px
;
}
}
// ----------------------------------------------------
m-chartV2
.isMini
{
margin-left
:
0
;
margin-top
:
24px
;
.js-plotly-plot
,
.plot-container
{
height
:
40px
;
min-height
:
40px
;
}
.m-chartV2__chartContainer
{
// margin-right: 24px;
}
.m-chartV2__hoverInfoDiv
{
width
:
150px
;
padding
:
0px
;
.m-chartV2__hoverInfo__wrapper
{
display
:
flex
;
}
.m-chartV2__hoverInfo__rowsContainer
{
display
:
flex
;
flex-direction
:
column
;
padding
:
14px
14px
14px
0
;
}
.m-chartV2__hoverInfo__arrowContainer
{
width
:
20px
;
i
{
margin-left
:
-4px
;
transform
:
rotate
(
-45deg
)
scaleX
(
0
.5
);
@include
m-theme
()
{
color
:
themed
(
$m-grey-600
);
}
}
}
[
class
*=
'm-chartV2__hoverInfo__row'
]
{
line-height
:
1
.1
;
}
.m-chartV2__hoverInfo__row--primary
{
font-size
:
12px
;
}
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
margin-left
:
0
;
}
}
src/app/common/components/chart-v2/chart-v2.component.spec.ts
View file @
321308e7
import
{
async
,
ComponentFixture
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
NO_ERRORS_SCHEMA
}
from
'
@angular/core
'
;
import
{
UtcDatePipe
}
from
'
../../pipes/utcdate
'
;
import
{
AbbrPipe
}
from
'
../../pipes/abbr
'
;
import
{
MockService
}
from
'
../../../utils/mock
'
;
import
{
ThemeService
}
from
'
../../services/theme.service
'
;
import
{
ChartV2Component
}
from
'
./chart-v2.component
'
;
describe
(
'
ChartV2Component
'
,
()
=>
{
...
...
@@ -8,14 +12,46 @@ describe('ChartV2Component', () => {
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
ChartV2Component
],
declarations
:
[
ChartV2Component
,
UtcDatePipe
,
AbbrPipe
],
providers
:
[
{
provide
:
ThemeService
,
useValue
:
MockService
(
ThemeService
),
},
],
schemas
:
[
NO_ERRORS_SCHEMA
],
}).
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
ChartV2Component
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
component
.
rawData
=
{
id
:
'
views
'
,
label
:
'
Pageviews
'
,
permissions
:
[
'
admin
'
,
'
user
'
],
unit
:
'
usd
'
,
description
:
''
,
visualisation
:
{
type
:
'
chart
'
,
segments
:
[
{
buckets
:
[
{
key
:
1567296000000
,
date
:
'
2019-09-01T00:00:00+00:00
'
,
value
:
11
,
},
{
key
:
1567382400000
,
date
:
'
2019-09-02T00:00:00+00:00
'
,
value
:
12
,
},
],
},
],
},
};
});
it
(
'
should create
'
,
()
=>
{
...
...
src/app/common/components/chart-v2/chart-v2.component.ts
View file @
321308e7
This diff is collapsed.
Click to expand it.
src/app/common/components/dashboard-layout/dashboard-layout.component.html
0 → 100644
View file @
321308e7
<div
class=
"m-dashboardLayout__header"
>
<ng-content
select=
"[m-dashboardLayout__header]"
></ng-content>
</div>
<div
class=
"m-dashboardLayout__body"
>
<ng-content
select=
"[m-dashboardLayout__body]"
></ng-content>
</div>
src/app/common/components/dashboard-layout/dashboard-layout.component.scss
0 → 100644
View file @
321308e7
m-dashboardLayout
{
display
:
block
;
width
:
100%
;
max-width
:
100%
;
}
.m-dashboardLayout__header
{
h3
{
font-size
:
26px
;
font-weight
:
500
;
margin-top
:
0
;
margin-right
:
24px
;
}
}
.m-dashboardLayout__body
{
position
:
relative
;
display
:
block
;
width
:
100%
;
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
m-dashboardLayout
{
display
:
block
;
padding
:
0
;
max-width
:
none
;
width
:
100%
;
}
.m-dashboardLayout__header
{
padding-left
:
24px
;
}
}
@media
screen
and
(
max-width
:
$max-mobile
)
{
}
src/app/common/components/
mini-chart/mini-char
t.component.spec.ts
→
src/app/common/components/
dashboard-layout/dashboard-layou
t.component.spec.ts
View file @
321308e7
import
{
async
,
ComponentFixture
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
MiniChar
tComponent
}
from
'
./
mini-char
t.component
'
;
import
{
DashboardLayou
tComponent
}
from
'
./
dashboard-layou
t.component
'
;
describe
(
'
MiniChar
tComponent
'
,
()
=>
{
let
component
:
MiniChar
tComponent
;
let
fixture
:
ComponentFixture
<
MiniChar
tComponent
>
;
describe
(
'
DashboardLayou
tComponent
'
,
()
=>
{
let
component
:
DashboardLayou
tComponent
;
let
fixture
:
ComponentFixture
<
DashboardLayou
tComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
MiniChar
tComponent
],
declarations
:
[
DashboardLayou
tComponent
],
}).
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
MiniChar
tComponent
);
fixture
=
TestBed
.
createComponent
(
DashboardLayou
tComponent
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
...
...
src/app/common/components/
mini-chart/mini-char
t.component.ts
→
src/app/common/components/
dashboard-layout/dashboard-layou
t.component.ts
View file @
321308e7
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
@
Component
({
selector
:
'
m-
miniChar
t
'
,
templateUrl
:
'
./
mini-char
t.component.html
'
,
selector
:
'
m-
dashboardLayou
t
'
,
templateUrl
:
'
./
dashboard-layou
t.component.html
'
,
})
export
class
MiniChar
tComponent
implements
OnInit
{
export
class
DashboardLayou
tComponent
implements
OnInit
{
constructor
()
{}
ngOnInit
()
{}
...
...
src/app/common/components/mini-chart/mini-chart.component.html
deleted
100644 → 0
View file @
9cb3a5b1
<p>
mini-chart works!
</p>
src/app/common/components/mini-chart/mini-chart.component.scss
deleted
100644 → 0
View file @
9cb3a5b1
src/app/common/components/page-layout/page-layout.component.html
0 → 100644
View file @
321308e7
<m-sidebarMenu
[catId]=
"navId"
></m-sidebarMenu>
<section
class=
"m-pageLayout__main"
>
<ng-content
select=
"[m-pageLayout__main]"
></ng-content>
</section>
src/app/common/components/page-layout/page-layout.component.scss
0 → 100644
View file @
321308e7
m-pageLayout
{
display
:
block
;
position
:
relative
;
width
:
100%
;
padding-top
:
56px
;
margin-bottom
:
48px
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
color
:
themed
(
$m-grey-800
);
}
.m-tooltip
{
margin-left
:
4px
;
i
{
font-size
:
12px
;
@include
m-theme
()
{
color
:
rgba
(
themed
(
$m-grey-300
)
,
0
.7
);
}
}
.m-tooltip--bubble
{
z-index
:
9999
;
font-size
:
11px
;
@include
m-theme
()
{
color
:
themed
(
$m-white
);
background-color
:
themed
(
$m-blue
);
}
}
}
}
m-sidebarMenu
{
display
:
block
;
box-sizing
:
border-box
;
padding-left
:
105px
;
width
:
245px
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
}
}
.m-pageLayout__main
{
margin-left
:
350px
;
margin-right
:
24px
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
color
:
themed
(
$m-grey-800
);
}
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
.m-pageLayout__main
{
display
:
block
;
margin
:
0
;
}
m-sidebarMenu
{
margin-left
:
0
;
}
}
src/app/common/components/page-layout/page-layout.component.spec.ts
0 → 100644
View file @
321308e7
import
{
async
,
ComponentFixture
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
Component
,
Input
}
from
'
@angular/core
'
;
import
{
PageLayoutComponent
}
from
'
./page-layout.component
'
;
@
Component
({
selector
:
'
m-sidebarMenu
'
,
template
:
''
,
})
class
SidebarMenuComponentMock
{
@
Input
()
catId
;
}
describe
(
'
PageLayoutComponent
'
,
()
=>
{
let
component
:
PageLayoutComponent
;
let
fixture
:
ComponentFixture
<
PageLayoutComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
PageLayoutComponent
,
SidebarMenuComponentMock
],
}).
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
PageLayoutComponent
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
it
(
'
should create
'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
src/app/common/components/page-layout/page-layout.component.ts
0 → 100644
View file @
321308e7
import
{
Component
,
OnInit
,
Input
}
from
'
@angular/core
'
;
@
Component
({
selector
:
'
m-pageLayout
'
,
templateUrl
:
'
./page-layout.component.html
'
,
})
export
class
PageLayoutComponent
implements
OnInit
{
@
Input
()
navId
:
string
;
constructor
()
{}
ngOnInit
()
{}
}
src/app/common/components/shadowbox-header/shadowbox-header.component.html
0 → 100644
View file @
321308e7
<section
class=
"m-shadowboxHeader__section"
>
<div
class=
"m-shadowboxHeader__wrapper"
>
<ng-container
*ngIf=
"isScrollable"
>
<div
*ngIf=
"isOverflown && !isAtScrollStart"
class=
"m-shadowboxHeader__overflowFade--left"
></div>
<div
[ngClass]=
"{ showButton: showButton.left }"
class=
"m-shadowboxHeader__overflowScrollButton--left"
(click)=
"slide('left')"
>
<i
class=
"material-icons"
>
chevron_left
</i>
</div>
</ng-container>
<div
#shadowboxHeaderContainer
class=
"m-shadowboxHeader__container disable-scrollbars"
(scroll)=
"onScroll($event)"
>
<ng-content
select=
".m-shadowboxLayout__header"
></ng-content>
</div>
<ng-container
*ngIf=
"isScrollable"
>
<div
*ngIf=
"isOverflown && !isAtScrollEnd"
class=
"m-shadowboxHeader__overflowFade--right"
></div>
<div
[ngClass]=
"{ showButton: showButton.right }"
class=
"m-shadowboxHeader__overflowScrollButton--right"
(click)=
"slide('right')"
>
<i
class=
"material-icons"
>
chevron_right
</i>
</div>
</ng-container>
</div>
</section>
src/app/common/components/shadowbox-header/shadowbox-header.component.scss
0 → 100644
View file @
321308e7
m-shadowboxHeader
{
min-height
:
116px
;
display
:
block
;
}
.m-shadowboxHeader__section
{
position
:
relative
;
}
.m-shadowboxHeader__wrapper
{
position
:
relative
;
z-index
:
1
;
height
:
124px
;
@include
m-theme
()
{
box-shadow
:
0
7px
15px
-7px
rgba
(
themed
(
$m-black-always
)
,
0
.1
);
}
}
.m-shadowboxHeader__container
{
overflow-x
:
hidden
;
overflow-y
:
hidden
;
// display: flex;
// flex-wrap: nowrap;
transition
:
all
0
.5s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
&
.disable-scrollbars
{
scrollbar-width
:
none
;
/* Firefox */
-ms-overflow-style
:
none
;
/* IE 10+ */
&
::-webkit-scrollbar
{
width
:
0px
;
background
:
transparent
;
/* Chrome/Safari/Webkit */
}
}
.m-tooltip--bubble
{
width
:
160px
;
}
}
[
class
*=
'm-shadowboxHeader__overflowFade--'
]
{
position
:
absolute
;
top
:
0
;
bottom
:
0
;
width
:
24px
;
z-index
:
2
;
&
.m-shadowboxHeader__overflowFade--right
{
@include
m-theme
()
{
right
:
0
;
background
:
linear-gradient
(
to
right
,
rgba
(
themed
(
$m-white
)
,
0
)
0
,
themed
(
$m-white
)
50%
);
}
}
&
.m-shadowboxHeader__overflowFade--left
{
@include
m-theme
()
{
left
:
0
;
background
:
linear-gradient
(
to
left
,
rgba
(
themed
(
$m-white
)
,
0
)
0
,
themed
(
$m-white
)
50%
);
}
}
}
[
class
*=
'm-shadowboxHeader__overflowScrollButton--'
]
{
position
:
absolute
;
top
:
50%
;
border-radius
:
50%
;
box-sizing
:
border-box
;
z-index
:
2
;
transform
:
translateY
(
-50%
);
opacity
:
0
;
transition
:
all
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
cursor
:
pointer
;
&
.showButton
{
opacity
:
1
;
}
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
box-shadow
:
0px
0px
10px
-3px
rgba
(
themed
(
$m-black-always
)
,
0
.3
);
border
:
1px
solid
themed
(
$m-white
);
}
&
:hover
{
@include
m-theme
()
{
border
:
1px
solid
themed
(
$m-blue
);
}
}
&
.m-shadowboxHeader__overflowScrollButton--right
{
right
:
-12
;
}
&
.m-shadowboxHeader__overflowScrollButton--left
{
left
:
-12
;
}
i
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-200
);
}
}
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
.m-shadowboxHeader__section
{
[
class
*=
'm-shadowboxHeader__overflowScrollButton--'
]
{
display
:
none
;
}
.m-shadowboxHeader__container
{
overflow-x
:
scroll
;
scroll-snap-type
:
x
mandatory
;
.m-analytics__metric
{
scroll-snap-align
:
start
;
&
:first-child
{
margin-left
:
16px
;
}
&
:last-child
{
margin-right
:
16px
;
}
}
}
}
.m-shadowboxHeader__wrapper
{
@include
m-theme
()
{
box-shadow
:
none
;
}
}
}
src/app/common/components/shadowbox-header/shadowbox-header.component.spec.ts
0 → 100644
View file @
321308e7
import
{
async
,
ComponentFixture
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
Component
,
Input
,
AfterViewInit
,
ChangeDetectionStrategy
,
ChangeDetectorRef
,
ViewChild
,
ElementRef
,
HostListener
,
}
from
'
@angular/core
'
;
import
{
ShadowboxHeaderComponent
}
from
'
./shadowbox-header.component
'
;
describe
(
'
ShadowboxHeaderComponent
'
,
()
=>
{
let
component
:
ShadowboxHeaderComponent
;
let
fixture
:
ComponentFixture
<
ShadowboxHeaderComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
ShadowboxHeaderComponent
],
}).
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
ShadowboxHeaderComponent
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
it
(
'
should create
'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
src/app/common/components/shadowbox-header/shadowbox-header.component.ts
0 → 100644
View file @
321308e7
import
{
Component
,
Input
,
AfterViewInit
,
ChangeDetectionStrategy
,
ChangeDetectorRef
,
ViewChild
,
ElementRef
,
HostListener
,
}
from
'
@angular/core
'
;
@
Component
({
selector
:
'
m-shadowboxHeader
'
,
templateUrl
:
'
./shadowbox-header.component.html
'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
ShadowboxHeaderComponent
implements
AfterViewInit
{
@
Input
()
isScrollable
:
boolean
=
true
;
@
Input
()
metricActivated
;
@
ViewChild
(
'
shadowboxHeaderContainer
'
,
{
static
:
false
})
shadowboxHeaderContainerEl
:
ElementRef
;
shadowboxHeaderContainer
;
childClientWidth
:
number
;
faderWidth
=
24
;
isOverflown
:
boolean
=
false
;
isAtScrollEnd
=
false
;
isAtScrollStart
=
true
;
showButton
=
{
left
:
false
,
right
:
false
};
constructor
(
private
cd
:
ChangeDetectorRef
)
{}
ngAfterViewInit
()
{
this
.
checkOverflow
();
// const activeMetric = ;//get the index of the metric with .active
// this.slideToActiveMetric();
}
// updateMetric(metric) {
// // TODO: if clicked metric is not fully visible, slide() until it is
// this.analyticsService.updateMetric(metric.id);
// }
// ----------------------------------------------------
@
HostListener
(
'
click
'
,
[
'
$event.target
'
])
onClick
(
target
)
{
console
.
log
(
'
***Clicked on:
'
,
target
);
// this.slideToActiveMetric(metricIndex);
}
slideToActiveMetric
(
metricIndex
)
{
// TODOOJM
}
// ----------------------------------------------------
@
HostListener
(
'
window:resize
'
)
onResize
()
{
this
.
checkOverflow
();
}
onScroll
(
$event
)
{
this
.
checkOverflow
();
}
checkOverflow
()
{
if
(
!
this
.
isScrollable
)
{
return
;
}
const
firstMetric
=
<
HTMLElement
>
(
document
.
querySelector
(
'
.m-shadowboxLayout__headerItem
'
)
);
// TODO: figure out how to avoid test failure "Cannot read property 'clientWidth' of null"
this
.
childClientWidth
=
firstMetric
?
firstMetric
.
clientWidth
:
160
;
this
.
shadowboxHeaderContainer
=
this
.
shadowboxHeaderContainerEl
.
nativeElement
;
this
.
isOverflown
=
this
.
shadowboxHeaderContainer
.
scrollWidth
-
this
.
shadowboxHeaderContainer
.
clientWidth
>
0
;
this
.
isAtScrollStart
=
this
.
shadowboxHeaderContainer
.
scrollLeft
<
this
.
faderWidth
;
this
.
showButton
.
left
=
this
.
isOverflown
&&
!
this
.
isAtScrollStart
;
this
.
isAtScrollEnd
=
!
this
.
isOverflown
||
this
.
shadowboxHeaderContainer
.
scrollWidth
-
(
this
.
shadowboxHeaderContainer
.
scrollLeft
+
this
.
shadowboxHeaderContainer
.
clientWidth
)
<
this
.
faderWidth
;
this
.
showButton
.
right
=
this
.
isOverflown
&&
this
.
shadowboxHeaderContainer
.
scrollLeft
>=
0
&&
!
this
.
isAtScrollEnd
;
this
.
detectChanges
();
}
slide
(
direction
)
{
let
currentScrollLeft
=
this
.
shadowboxHeaderContainer
.
scrollLeft
;
let
targetScrollLeft
;
let
scrollEndOffset
=
0
;
const
partiallyVisibleMetricWidth
=
this
.
shadowboxHeaderContainer
.
clientWidth
%
this
.
childClientWidth
;
const
completelyVisibleMetricsWidth
=
this
.
shadowboxHeaderContainer
.
clientWidth
-
partiallyVisibleMetricWidth
;
if
(
direction
===
'
right
'
)
{
if
(
currentScrollLeft
<
this
.
faderWidth
)
{
currentScrollLeft
=
this
.
faderWidth
;
}
targetScrollLeft
=
Math
.
min
(
currentScrollLeft
+
completelyVisibleMetricsWidth
,
this
.
shadowboxHeaderContainer
.
scrollWidth
-
completelyVisibleMetricsWidth
);
}
else
{
if
(
this
.
isAtScrollEnd
)
{
scrollEndOffset
=
partiallyVisibleMetricWidth
-
this
.
faderWidth
;
}
targetScrollLeft
=
Math
.
max
(
currentScrollLeft
-
completelyVisibleMetricsWidth
+
scrollEndOffset
,
0
);
}
this
.
shadowboxHeaderContainer
.
scrollTo
({
top
:
0
,
left
:
targetScrollLeft
,
behavior
:
'
smooth
'
,
});
}
detectChanges
()
{
this
.
cd
.
markForCheck
();
this
.
cd
.
detectChanges
();
}
}
Prev
1
2
3
Next