Work on refactoring measurements out of Lesion Tracker package
- Removed AssociatedStudies Collection - Measurement API is generated from configuration files - Data exchange methods are defined in configuration
This commit is contained in:
1 parent
c511edd419
commit
ab4d4c9008
537 files changed
+5122
-3545
No files matched your search
+12
@@ -0,0 +1,12 @@
|
||||
<template name="studyTimepoint">
|
||||
<div class="studyTimepointWrapper">
|
||||
<div class="studyTimepoint">
|
||||
{{#each study in studies}}
|
||||
{{>studyTimepointStudy (clone this
|
||||
study=study
|
||||
active=(isActive study)
|
||||
)}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
Template.studyTimepoint.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
instance.isActive = {};
|
||||
});
|
||||
|
||||
// Initialize the timepoint wrapper max-height to enable CSS transition
|
||||
Template.studyTimepoint.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
const $studies = instance.$('.studyTimepoint');
|
||||
const $wrapper = $studies.closest('.studyTimepointWrapper');
|
||||
const $timepoint = $wrapper.closest('.timepointEntry');
|
||||
const studiesVisible = $studies.is(':visible');
|
||||
|
||||
if (!studiesVisible) {
|
||||
$timepoint.addClass('active');
|
||||
}
|
||||
|
||||
// Recalculates the timepoint height to make CSS transition smoother
|
||||
$studies.trigger('displayStateChanged');
|
||||
|
||||
if (!studiesVisible) {
|
||||
$timepoint.removeClass('active');
|
||||
}
|
||||
});
|
||||
|
||||
Template.studyTimepoint.events({
|
||||
// Changes the selected study
|
||||
'selectionChanged .studyTimepoint'(event, instance, changed) {
|
||||
const $selection = $(changed.selection);
|
||||
|
||||
// Defines where will be the studies searched
|
||||
let $studiesTarget = instance.$('.studyTimepoint');
|
||||
|
||||
if (changed.isQuickSwitch) {
|
||||
// Changes the current quick switch study
|
||||
const study = ViewerStudies.findOne({
|
||||
studyInstanceUid: changed.studyInstanceUid
|
||||
});
|
||||
instance.data.currentStudy.set(study);
|
||||
|
||||
// Changes the target to toggle the selection in all the studies
|
||||
$studiesTarget = $studiesTarget.closest('.studyTimepointBrowser');
|
||||
}
|
||||
|
||||
// Removes selected state from all studies but the triggered study
|
||||
$studiesTarget.find('.studyTimepointStudy').not($selection).removeClass('active');
|
||||
|
||||
if (changed.isQuickSwitch) {
|
||||
// Reset active studies map to allow only one active study
|
||||
instance.isActive = {};
|
||||
// Add selected state for the triggered study
|
||||
$selection.addClass('active');
|
||||
} else {
|
||||
const $timepoint = instance.$('.studyTimepoint');
|
||||
// Set the max-height to inherit to be able to expand the wrapper on its full height
|
||||
instance.$('.studyTimepointWrapper').css('max-height', 'inherit');
|
||||
// Toggle selected state for the triggered study
|
||||
$selection.removeClass('loading');
|
||||
$selection.toggleClass('active');
|
||||
// Recalculates the timepoint height to make CSS transition smoother
|
||||
const $thumbnails = $selection.find('.studyTimepointThumbnails');
|
||||
$thumbnails.one('transitionend', () => $timepoint.trigger('displayStateChanged'));
|
||||
}
|
||||
|
||||
// Set the current study as active
|
||||
instance.isActive[changed.studyInstanceUid] = $selection.hasClass('active');
|
||||
},
|
||||
// It should be triggered when the timepoint height is changed
|
||||
'displayStateChanged .studyTimepoint'(event, instance) {
|
||||
const $timepoint = $(event.currentTarget);
|
||||
const $wrapper = $timepoint.closest('.studyTimepointWrapper');
|
||||
|
||||
// Set the max-height for the wrapper to make CSS transition smoother
|
||||
$wrapper.css('max-height', $timepoint.height());
|
||||
}
|
||||
});
|
||||
|
||||
Template.studyTimepoint.helpers({
|
||||
isActive(study) {
|
||||
const instance = Template.instance();
|
||||
|
||||
if (!study.studyInstanceUid) {
|
||||
return;
|
||||
}
|
||||
|
||||
return instance.isActive[study.studyInstanceUid];
|
||||
}
|
||||
});
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
@import "{design}/app"
|
||||
|
||||
.studyTimepointWrapper
|
||||
overflow: hidden
|
||||
transition($sidebarTransition)
|
||||
|
||||
.timepointEntry:not(.active) .studyTimepointWrapper
|
||||
max-height: 0 !important
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
<template name="studyTimepointBrowser">
|
||||
{{#let timepointList=timepoints}}
|
||||
<div class="studyTimepointBrowser noselect {{#if shallShowViewType timepointList}}viewTypeVisible{{/if}}">
|
||||
<div class="timepointButtonContainer p-t-2">
|
||||
{{>roundedButtonGroup viewTypeButtonGroupData}}
|
||||
</div>
|
||||
<div class="studyTimepointScrollArea">
|
||||
<div class="p-l-1">
|
||||
{{#if timepointList.length}}
|
||||
{{#each timepoint in timepointList}}
|
||||
<div class="timepointEntry p-y-2">
|
||||
<div class="timepointHeader">
|
||||
<div class="timepointDetails clearfix">
|
||||
<div class="timepointFollowupTitle pull-left">
|
||||
{{timepointApi.title timepoint}}
|
||||
</div>
|
||||
<div class="expandIcon pull-right">
|
||||
<i class="fa fa-chevron-down"></i>
|
||||
</div>
|
||||
<div class="timepointDate pull-right m-r-1">{{formatDA timepoint.earliestDate 'D-MMM-YYYY'}}</div>
|
||||
</div>
|
||||
<div class="timepointModalities">{{modalitiesSummary timepoint}}</div>
|
||||
</div>
|
||||
{{>studyTimepoint studies=(studies timepoint) index=@index viewportIndex=this.viewportIndex currentStudy=this.currentStudy}}
|
||||
</div>
|
||||
<hr>
|
||||
{{/each}}
|
||||
{{#if and this.currentStudy (not showAdditionalTimepoints)}}
|
||||
<div class="studyModality additional">
|
||||
Show additional timepoints
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="p-t-2">
|
||||
{{>studyTimepoint (clone this studies=studies)}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/let}}
|
||||
</template>
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
Template.studyTimepointBrowser.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Reactive variable to control the view type for all or key timepoints
|
||||
instance.timepointViewType = new ReactiveVar(instance.data.timepointViewType);
|
||||
|
||||
// Defines whether to show all key timepoints or only the current one
|
||||
instance.showAdditionalTimepoints = new ReactiveVar(true);
|
||||
|
||||
// Return the current study if it's defined
|
||||
instance.getCurrentStudy = () => {
|
||||
return instance.data.currentStudy && instance.data.currentStudy.get();
|
||||
};
|
||||
|
||||
// Get the studies for a specific timepoint
|
||||
instance.getStudies = timepoint => {
|
||||
if (!timepoint) {
|
||||
return ViewerStudies.find().fetch();
|
||||
}
|
||||
|
||||
return timepoint.studyInstanceUids.map(studyInstanceUid => {
|
||||
const query = {
|
||||
patientId: timepoint.patientId,
|
||||
studyInstanceUid: studyInstanceUid
|
||||
};
|
||||
|
||||
var loadedStudy = ViewerStudies.findOne(query);
|
||||
if (loadedStudy) {
|
||||
return loadedStudy;
|
||||
}
|
||||
|
||||
var notYetLoaded = StudyListStudies.findOne(query);
|
||||
if (!notYetLoaded) {
|
||||
throw 'No study data available for Study: ' + studyInstanceUid;
|
||||
}
|
||||
|
||||
return notYetLoaded;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
Template.studyTimepointBrowser.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
instance.autorun(() => {
|
||||
// Runs this computation every time the timepointViewType is changed
|
||||
const type = instance.timepointViewType.get();
|
||||
|
||||
// Removes all active classes to collapse the timepoints and studies
|
||||
instance.$('.timepointEntry, .studyTimepointStudy').removeClass('active');
|
||||
if (type === 'key') {
|
||||
// Show only first timepoint expanded for key timepoints
|
||||
instance.$('.timepointEntry:first').addClass('active');
|
||||
}
|
||||
});
|
||||
|
||||
let lastStudy;
|
||||
instance.autorun(() => {
|
||||
// Runs this computation every time the curenty study is changed
|
||||
const currentStudy = instance.data.currentStudy && instance.data.currentStudy.get();
|
||||
|
||||
// Check if the study really changed and update the last study
|
||||
if (currentStudy !== lastStudy) {
|
||||
instance.showAdditionalTimepoints.set(false);
|
||||
lastStudy = currentStudy;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.studyTimepointBrowser.events({
|
||||
'click .timepointHeader'(event, instance) {
|
||||
const $timepoint = $(event.currentTarget).closest('.timepointEntry');
|
||||
|
||||
// Recalculates the timepoint height to make CSS transition smoother
|
||||
$timepoint.find('.studyTimepoint').trigger('displayStateChanged');
|
||||
|
||||
// Toggle active class to group/ungroup timepoint studies
|
||||
$timepoint.toggleClass('active');
|
||||
},
|
||||
|
||||
'click .studyModality.additional'(event, instance) {
|
||||
// Show all key timepoints
|
||||
instance.showAdditionalTimepoints.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
Template.studyTimepointBrowser.helpers({
|
||||
// Decides if the timepoint view type switch shall be shown or omitted
|
||||
shallShowViewType(timepointList) {
|
||||
const instance = Template.instance();
|
||||
return timepointList.length && !instance.data.timepointViewType;
|
||||
},
|
||||
|
||||
// Returns the button group data for switching between timepoint view types
|
||||
viewTypeButtonGroupData() {
|
||||
return {
|
||||
value: Template.instance().timepointViewType,
|
||||
options: [{
|
||||
value: 'key',
|
||||
text: 'Key Timepoints'
|
||||
}, {
|
||||
value: 'all',
|
||||
text: 'All Timepoints'
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
// Defines whether to show all key timepoints or only the current one
|
||||
showAdditionalTimepoints() {
|
||||
return Template.instance().showAdditionalTimepoints.get();
|
||||
},
|
||||
|
||||
// Get the timepoints to be listed
|
||||
timepoints() {
|
||||
const instance = Template.instance();
|
||||
// Get the current study
|
||||
const currentStudy = instance.getCurrentStudy();
|
||||
// Declare the timepoints
|
||||
let timepoints;
|
||||
if (currentStudy && !instance.showAdditionalTimepoints.get()) {
|
||||
// Show only the current study's timepoint
|
||||
timepoints = instance.data.timepointApi.study(currentStudy.studyInstanceUid);
|
||||
} else {
|
||||
if (!instance.data.timepointApi) {
|
||||
// If there is no timepoint API defined whatsoever, this means that there is no
|
||||
// current timepoint ID, so we can just display all of the currently loaded studies
|
||||
// in the study sidebar
|
||||
timepoints = [];
|
||||
} else if (instance.timepointViewType.get() === 'all') {
|
||||
// Show all timepoints
|
||||
timepoints = instance.data.timepointApi.all();
|
||||
} else {
|
||||
// Show only key timepoints
|
||||
timepoints = instance.data.timepointApi.key();
|
||||
}
|
||||
}
|
||||
// Returns the timepoints
|
||||
return timepoints;
|
||||
},
|
||||
|
||||
// Get the studies for a specific timepoint
|
||||
studies(timepoint) {
|
||||
return Template.instance().getStudies(timepoint);
|
||||
},
|
||||
|
||||
// Build the modalities summary for all timepoint's studies
|
||||
modalitiesSummary(timepoint) {
|
||||
const instance = Template.instance();
|
||||
|
||||
const studies = instance.getStudies(timepoint);
|
||||
|
||||
const modalities = {};
|
||||
studies.forEach(study => {
|
||||
const modality = study.modalities || 'UN';
|
||||
modalities[modality] = modalities[modality] + 1 || 1;
|
||||
});
|
||||
|
||||
const result = [];
|
||||
_.each(modalities, (count, modality) => {
|
||||
result.push(`${count} ${modality}`);
|
||||
});
|
||||
|
||||
return result.join(', ');
|
||||
}
|
||||
});
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
@import "{design}/app"
|
||||
|
||||
$timepointButtonHeight = 55px
|
||||
|
||||
.studyTimepointBrowser
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
float: left
|
||||
height: 100%
|
||||
position: relative
|
||||
width: 100%
|
||||
|
||||
.timepointButtonContainer
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
theme('border-bottom', '1px solid $uiBorderColor')
|
||||
display: none
|
||||
height: $timepointButtonHeight
|
||||
left: 10px
|
||||
position: absolute
|
||||
right: 10px
|
||||
top: 0
|
||||
z-index: 1
|
||||
|
||||
&.viewTypeVisible
|
||||
|
||||
.timepointButtonContainer
|
||||
display: block
|
||||
|
||||
.studyTimepointScrollArea
|
||||
padding-top: $timepointButtonHeight
|
||||
|
||||
.timepointEntry
|
||||
&.active
|
||||
.timepointModalities
|
||||
height: 0
|
||||
.timepointDate
|
||||
display: none
|
||||
.expandIcon i
|
||||
transform: rotateX(180deg)
|
||||
.timepointFollowupTitle
|
||||
font-size: 14px
|
||||
theme('color', '$textSecondaryColor')
|
||||
text-transform: uppercase
|
||||
|
||||
.timepointHeader
|
||||
cursor: pointer
|
||||
font-size: 13px
|
||||
|
||||
&
|
||||
.expandIcon i
|
||||
.timepointFollowupTitle
|
||||
.timepointDate
|
||||
.timepointModalities
|
||||
theme('color', '$textSecondaryColor')
|
||||
transition($sidebarTransition)
|
||||
|
||||
&:hover
|
||||
&
|
||||
.timepointFollowupTitle
|
||||
.expandIcon i
|
||||
.timepointDate
|
||||
.timepointModalities
|
||||
theme('color', '$textPrimaryColor') !important
|
||||
|
||||
.timepointDetails
|
||||
.timepointModalities
|
||||
line-height: 25px
|
||||
|
||||
.timepointModalities
|
||||
height: 25px
|
||||
overflow: hidden
|
||||
|
||||
.expandIcon i
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
.timepointFollowupTitle
|
||||
theme('color', '$textPrimaryColor')
|
||||
padding-top: 2px
|
||||
|
||||
.studyTimepointScrollArea
|
||||
height: 100%
|
||||
overflow-x: hidden
|
||||
overflow-y: auto
|
||||
margin-right: -22px
|
||||
padding-bottom: 20px
|
||||
padding-right: 16px
|
||||
|
||||
&::-webkit-scrollbar
|
||||
display: none
|
||||
|
||||
hr, .timepointHeader, .studyItem, .studyModality.additional
|
||||
margin-right: 16px
|
||||
|
||||
.studySidebarTimepoint .thumbnailEntry.active:before
|
||||
theme('background-color', '$activeColor')
|
||||
border-top-right-radius: 7px
|
||||
border-bottom-right-radius: 7px
|
||||
content: ''
|
||||
display: block
|
||||
height: 91px
|
||||
pointer-events: none
|
||||
position: fixed
|
||||
right: 0
|
||||
top: 0
|
||||
width: 5px
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<template name="studyTimepointStudy">
|
||||
{{#let isSidebar=(isUndefined viewportIndex)}}
|
||||
<div class="studyTimepointStudy {{#if isSidebar}}studySidebarTimepoint{{else}}studyQuickSwitchTimepoint{{/if}} {{#if this.active}}active{{/if}}">
|
||||
<div class="studyItem">
|
||||
{{>loadingText}}
|
||||
<div class="studyModality">
|
||||
<div class="studyModalityBox">
|
||||
<div class="studyModalityText" style="{{modalityStyle}}">
|
||||
{{#if this.study.modalities}}
|
||||
{{ modalities }}
|
||||
{{else}}
|
||||
UN
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="studyText">
|
||||
<div class="studyDate">{{formatDA this.study.studyDate 'D-MMM-YYYY'}}</div>
|
||||
<div class="studyDescription">{{this.study.studyDescription}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if isSidebar}}
|
||||
<div class="studyTimepointThumbnails">
|
||||
{{#each thumbnail in (studyThumbnails this.study)}}
|
||||
{{>thumbnailEntry (clone this thumbnail=thumbnail)}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/let}}
|
||||
</template>
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
Template.studyTimepointStudy.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Set the current study as selected in the studies list
|
||||
instance.select = (isQuickSwitch=false) => {
|
||||
const $study = instance.$('.studyTimepointStudy');
|
||||
const $timepoint = $study.closest('.studyTimepoint');
|
||||
|
||||
const selectionChanged = {
|
||||
selection: [$study[0]],
|
||||
studyInstanceUid: instance.data.study.studyInstanceUid,
|
||||
isQuickSwitch
|
||||
};
|
||||
|
||||
$timepoint.trigger('selectionChanged', selectionChanged);
|
||||
};
|
||||
});
|
||||
|
||||
// Initialize the study wrapper max-height to enable CSS transition
|
||||
Template.studyTimepointStudy.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
const $study = instance.$('.studyTimepointStudy');
|
||||
const $thumbnails = instance.$('.studyTimepointThumbnails');
|
||||
$study.addClass('active');
|
||||
$thumbnails.css('max-height', $thumbnails.height());
|
||||
$study.removeClass('active');
|
||||
|
||||
// Here we add, remove, and add the active class again because this way
|
||||
// the max-height animation appears smooth to the user.
|
||||
if (instance.data.active) {
|
||||
Meteor.setTimeout(() => {
|
||||
$study.addClass('active');
|
||||
}, 1);
|
||||
}
|
||||
});
|
||||
|
||||
Template.studyTimepointStudy.helpers({
|
||||
modalities() {
|
||||
const instance = Template.instance();
|
||||
let modalities = instance.data.study.modalities;
|
||||
|
||||
// Replace backslashes with spaces
|
||||
return modalities.replace(/\\/g, ' ');
|
||||
},
|
||||
|
||||
modalityStyle() {
|
||||
// Responsively styles the Modality Acronyms for studies
|
||||
// with more than one modality
|
||||
const instance = Template.instance();
|
||||
const modalities = instance.data.study.modalities || 'UN';
|
||||
const numModalities = modalities.split(/\\/g).length;
|
||||
|
||||
if (numModalities === 1) {
|
||||
// If we have only one modality, it should take up the whole
|
||||
// div.
|
||||
return 'font-size: 1vw';
|
||||
} else if (numModalities === 2) {
|
||||
// If we have two, let them sit side-by-side
|
||||
return 'font-size: 0.75vw';
|
||||
} else {
|
||||
// If we have more than two modalities, change the line
|
||||
// height to display multiple rows, depending on the number
|
||||
// of modalities we need to display.
|
||||
const lineHeight = Math.ceil(numModalities / 2) * 1.2;
|
||||
return 'line-height: ' + lineHeight + 'vh';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Template.studyTimepointStudy.events({
|
||||
// Recalculates the timepoint height to make CSS transition smoother
|
||||
'transitionend .studyTimepointThumbnails'(event, instance) {
|
||||
if (event.target === event.currentTarget) {
|
||||
$(event.currentTarget).closest('.studyTimepoint').trigger('displayStateChanged');
|
||||
}
|
||||
},
|
||||
|
||||
// Transfers the active state to the current study
|
||||
'click .studyQuickSwitchTimepoint .studyModality'(event, instance) {
|
||||
instance.select(true);
|
||||
},
|
||||
|
||||
// Changes the current study selection for the clicked study
|
||||
'click .studyModality'(event, instance) {
|
||||
const $study = $(event.currentTarget).closest('.studyTimepointStudy');
|
||||
|
||||
const studyData = instance.data.study;
|
||||
const studyInstanceUid = studyData.studyInstanceUid;
|
||||
|
||||
const isQuickSwitch = !_.isUndefined(instance.data.viewportIndex);
|
||||
|
||||
// Check if the study already has series data,
|
||||
// and if not, retrieve it.
|
||||
if (!studyData.seriesList) {
|
||||
const alreadyLoaded = ViewerStudies.findOne({
|
||||
studyInstanceUid
|
||||
});
|
||||
|
||||
if (!alreadyLoaded) {
|
||||
$study.addClass('loading');
|
||||
getStudyMetadata(studyInstanceUid, study => {
|
||||
study.displaySets = createStacks(study);
|
||||
ViewerStudies.insert(study);
|
||||
instance.select(isQuickSwitch);
|
||||
});
|
||||
} else {
|
||||
studyData.seriesList = alreadyLoaded.seriesList;
|
||||
}
|
||||
} else {
|
||||
instance.select(isQuickSwitch);
|
||||
}
|
||||
}
|
||||
});
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
@import "{design}/app"
|
||||
|
||||
$boxBorderColor = transparent
|
||||
$boxHoverBackgroundColor = #14191E
|
||||
$boxHoverBorderColor = #2d4660
|
||||
$boxActiveBorderColor = #131D29
|
||||
$boxWidth = 50px
|
||||
$borderThickness = 2px
|
||||
$boxBorderRadius = 8px
|
||||
$nestingMargin = 6px
|
||||
$spacerX = 7px
|
||||
$spacerY = 12px
|
||||
|
||||
.studyTimepointStudy
|
||||
position: relative
|
||||
// required transformation to make inner fixed elements relative to this one
|
||||
transform(scale(1))
|
||||
|
||||
.loadingTextDiv
|
||||
padding: 25px
|
||||
border-radius: 12px
|
||||
position: absolute
|
||||
opacity: 0
|
||||
z-index: 100
|
||||
background-color: $boxHoverBackgroundColor
|
||||
pointer-events: none
|
||||
margin: 0
|
||||
|
||||
&.loading
|
||||
.loadingTextDiv
|
||||
height: 100%
|
||||
left: 0
|
||||
opacity: 0.75
|
||||
right: 16px
|
||||
|
||||
.studyModality
|
||||
opacity: 0.2
|
||||
|
||||
&.active
|
||||
.studyModality
|
||||
.studyModalityBox
|
||||
theme('color', '$primaryBackgroundColor')
|
||||
&
|
||||
&:before
|
||||
&:after
|
||||
theme('background-color', '$activeColor')
|
||||
border-color: $boxActiveBorderColor
|
||||
|
||||
&:not(.active) .studyTimepointThumbnails
|
||||
max-height: 0 !important
|
||||
|
||||
.studyTimepointThumbnails
|
||||
overflow: hidden
|
||||
transition($sidebarTransition)
|
||||
|
||||
.studyModality
|
||||
border: 1px solid $boxBorderColor
|
||||
border-radius: 12px
|
||||
cursor: pointer
|
||||
padding: $spacerY $spacerX ($spacerY - 1)
|
||||
position: relative
|
||||
transition($sidebarTransition)
|
||||
z-index: 1
|
||||
|
||||
&:hover
|
||||
background-color: $boxHoverBackgroundColor
|
||||
border-color: $boxHoverBorderColor
|
||||
|
||||
&.additional
|
||||
theme('color', '$textSecondaryColor')
|
||||
|
||||
&.additional
|
||||
theme('color', '$textPrimaryColor')
|
||||
font-size: 16px
|
||||
font-weight: normal
|
||||
height: 91px
|
||||
line-height: 91px
|
||||
padding: 0
|
||||
text-align: center
|
||||
|
||||
.studyText
|
||||
font-size: 13px
|
||||
left: ($spacerX * 3) + $boxWidth + ($nestingMargin * 3)
|
||||
line-height: 14px
|
||||
position: absolute
|
||||
right: $spacerX
|
||||
top: $spacerY
|
||||
.studyDate
|
||||
margin-top: 8px
|
||||
theme('color', '$textSecondaryColor')
|
||||
.studyDescription
|
||||
margin-top: 8px
|
||||
theme('color', '$textPrimaryColor')
|
||||
|
||||
.studyModalityBox
|
||||
theme('color', '$textSecondaryColor')
|
||||
line-height: $boxWidth
|
||||
margin-left: $nestingMargin * 2
|
||||
margin-top: $nestingMargin * 2
|
||||
position: relative
|
||||
|
||||
.studyModalityText
|
||||
text-align: center
|
||||
text-transform: uppercase
|
||||
height: 100%
|
||||
|
||||
&
|
||||
&:before
|
||||
&:after
|
||||
theme('border', '$borderThickness solid $primaryBackgroundColor')
|
||||
theme('background-color', '$boxBackgroundColor')
|
||||
border-radius: $boxBorderRadius
|
||||
height: $boxWidth + ($borderThickness * 2)
|
||||
transition($sidebarTransition)
|
||||
width: $boxWidth + ($borderThickness * 2)
|
||||
|
||||
&:before
|
||||
&:after
|
||||
display: block
|
||||
content: ''
|
||||
position: absolute
|
||||
|
||||
&:before
|
||||
top: -($borderThickness + $nestingMargin)
|
||||
left: -($borderThickness + $nestingMargin)
|
||||
z-index: -1
|
||||
|
||||
&:after
|
||||
top: -($borderThickness + ($nestingMargin * 2))
|
||||
left: -($borderThickness + ($nestingMargin * 2))
|
||||
z-index: -2
|
||||
Reference in new issue
Block a user