mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
Courses UI: Add course details condensed progress view
Defaulting to condensed view, with checkbox to expand details.
This commit is contained in:
parent
cf720ce270
commit
f966b8a2fc
3 changed files with 113 additions and 58 deletions
|
@ -23,7 +23,6 @@
|
|||
font-size: 9pt
|
||||
font-weight: normal
|
||||
border: 1px solid gray
|
||||
border-radius: 5px
|
||||
margin: 0px
|
||||
padding: 2px
|
||||
background-color: white
|
||||
|
@ -62,10 +61,10 @@
|
|||
cursor: default
|
||||
display: inline-block
|
||||
white-space: nowrap
|
||||
font-size: 9pt
|
||||
font-size: 12px
|
||||
line-height: 12px
|
||||
font-weight: normal
|
||||
border: 1px solid gray
|
||||
border-radius: 5px
|
||||
margin: 0px
|
||||
padding: 2px
|
||||
|
||||
|
@ -83,7 +82,7 @@
|
|||
font-size: 14px
|
||||
|
||||
.student-cell
|
||||
min-width: 150px
|
||||
width: 150px
|
||||
|
||||
.progress-cell
|
||||
padding: 2px
|
||||
|
@ -114,9 +113,9 @@
|
|||
.progress-level-cell
|
||||
display: inline-block
|
||||
white-space: nowrap
|
||||
font-size: 9pt
|
||||
font-size: 12px
|
||||
line-height: 12px
|
||||
border: 1px solid gray
|
||||
border-radius: 5px
|
||||
margin: 0px
|
||||
padding: 2px
|
||||
|
||||
|
@ -131,9 +130,9 @@
|
|||
.progress-concept-cell
|
||||
display: inline-block
|
||||
white-space: nowrap
|
||||
font-size: 9pt
|
||||
font-size: 12px
|
||||
line-height: 12px
|
||||
border: 1px solid gray
|
||||
border-radius: 5px
|
||||
margin: 0px
|
||||
padding: 2px
|
||||
|
||||
|
@ -142,3 +141,6 @@
|
|||
|
||||
.progress-concept-cell-complete
|
||||
background-color: lightgray
|
||||
|
||||
.condense-progress
|
||||
width: 100%
|
||||
|
|
|
@ -147,60 +147,107 @@ mixin progress-tab
|
|||
span.progress-key.progress-key-complete complete
|
||||
span.progress-key.progress-key-started started
|
||||
span.progress-key not started
|
||||
if maxLastStartedIndex > 30
|
||||
input.expand-progress-checkbox(type='checkbox')
|
||||
span.spl.expand-progress-label(data-i18n="clans.exp_levels") Expand levels
|
||||
input.expand-progress-checkbox(type='checkbox')
|
||||
span.spl.expand-progress-label Expand details
|
||||
tbody
|
||||
each student in instance.students
|
||||
tr
|
||||
td.student-cell
|
||||
a= student
|
||||
- var levelsCompleted = 0
|
||||
each level in course.levels
|
||||
if userLevelStateMap[student][level] === 'complete'
|
||||
- levelsCompleted++
|
||||
- var secondsPlayed = Math.round(Math.random() * 1000 * (levelsCompleted + 1))
|
||||
- var secondsLastPlayed = Math.round(Math.random() * 100000)
|
||||
div #{levelsCompleted} levels completed
|
||||
div #{moment.duration(secondsPlayed, 'seconds').humanize()} played
|
||||
div Played #{moment().subtract(secondsLastPlayed, 'seconds').fromNow()}
|
||||
div #{stats[student].levelsCompleted} levels completed
|
||||
div #{moment.duration(stats[student].secondsPlayed, 'seconds').humanize()} played
|
||||
div Played #{moment().subtract(stats[student].secondsLastPlayed, 'seconds').fromNow()}
|
||||
td.progress-cell
|
||||
.level-progression-concepts Concepts
|
||||
each concept in courseConcepts
|
||||
if userConceptsMap[student] && userConceptsMap[student][concept] === 'complete'
|
||||
span.spr.progress-concept-cell.progress-concept-cell-complete(data-i18n="concepts." + concept)
|
||||
else if userConceptsMap[student] && userConceptsMap[student][concept] === 'started'
|
||||
span.spr.progress-concept-cell.progress-concept-cell-started(data-i18n="concepts." + concept)
|
||||
else
|
||||
span.spr.progress-concept-cell.progress-concept-cell-not-started(data-i18n="concepts." + concept)
|
||||
if showExpandedProgress
|
||||
.level-progression-concepts Concepts
|
||||
each concept in courseConcepts
|
||||
if userConceptsMap[student] && userConceptsMap[student][concept] === 'complete'
|
||||
span.spr.progress-concept-cell.progress-concept-cell-complete(data-i18n="concepts." + concept)
|
||||
else if userConceptsMap[student] && userConceptsMap[student][concept] === 'started'
|
||||
span.spr.progress-concept-cell.progress-concept-cell-started(data-i18n="concepts." + concept)
|
||||
else
|
||||
span.spr.progress-concept-cell.progress-concept-cell-not-started(data-i18n="concepts." + concept)
|
||||
|
||||
.level-progression-levels Levels
|
||||
- var i = 0
|
||||
each level in course.levels
|
||||
if userLevelStateMap[student][level] === 'complete'
|
||||
span.progress-level-cell.progress-level-cell-complete #{i + 1}
|
||||
if showExpandedProgress || i === 0 || i === course.levels.length - 1
|
||||
.level-progression-levels Levels
|
||||
- var i = 0
|
||||
each level in course.levels
|
||||
if userLevelStateMap[student][level] === 'complete'
|
||||
span.progress-level-cell.progress-level-cell-complete #{i + 1}
|
||||
span.spl= level.replace('Course: ', '')
|
||||
.level-popup-container
|
||||
h3 #{i + 1}. #{level.replace('Course: ', '')}
|
||||
p
|
||||
div
|
||||
.level-popup-container
|
||||
h3 #{i + 1}. #{level.replace('Course: ', '')}
|
||||
p
|
||||
- var playTime = Math.round(Math.random() * 600)
|
||||
span Time to solve
|
||||
span : #{moment.duration(playTime, "seconds").humanize()}
|
||||
div
|
||||
p
|
||||
- var completionDate = new Date()
|
||||
- completionDate.setUTCDate(completionDate.getUTCDate() - Math.round(Math.random() * 60))
|
||||
span Completed on
|
||||
span : #{moment(completionDate).format('MMMM Do YYYY, h:mm:ss a')}
|
||||
strong(data-i18n="clans.view_solution") Click to view solution.
|
||||
else if userLevelStateMap[student][level] === 'started'
|
||||
span.progress-level-cell.progress-level-cell-started #{i + 1} #{level.replace('Course: ', '')}
|
||||
else
|
||||
span.progress-level-cell.level-progression-level-not-started #{i + 1}
|
||||
if showExpandedProgress || i === 0
|
||||
span.spl= level.replace('Course: ', '')
|
||||
- i++
|
||||
strong(data-i18n="clans.view_solution") Click to view solution.
|
||||
else if userLevelStateMap[student][level] === 'started'
|
||||
span.progress-level-cell.progress-level-cell-started #{i + 1} #{level.replace('Course: ', '')}
|
||||
.level-popup-container
|
||||
h3 #{i + 1}. #{level.replace('Course: ', '')}
|
||||
p
|
||||
- var completionDate = new Date()
|
||||
- completionDate.setUTCDate(completionDate.getUTCDate() - Math.round(Math.random() * 60))
|
||||
span Last played on
|
||||
span : #{moment(completionDate).format('MMMM Do YYYY, h:mm:ss a')}
|
||||
strong(data-i18n="clans.view_solution") Click to view solution.
|
||||
else
|
||||
span.progress-level-cell.level-progression-level-not-started #{i + 1} #{level.replace('Course: ', '')}
|
||||
- i++
|
||||
else
|
||||
//- Condensed view
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
td
|
||||
.level-progression-concepts(style='margin:0px;') Concepts
|
||||
td.condense-progress
|
||||
each concept in courseConcepts
|
||||
if userConceptsMap[student] && userConceptsMap[student][concept] === 'complete'
|
||||
span.spr.progress-concept-cell.progress-concept-cell-complete(data-i18n="concepts." + concept)
|
||||
else if userConceptsMap[student] && userConceptsMap[student][concept] === 'started'
|
||||
span.spr.progress-concept-cell.progress-concept-cell-started(data-i18n="concepts." + concept)
|
||||
else
|
||||
break
|
||||
tr
|
||||
td
|
||||
.level-progression-levels(style='margin:0px;') Levels
|
||||
td.condense-progress
|
||||
- var levelCellWidth = 100.00 / course.levels.length
|
||||
- var i = 0
|
||||
each level in course.levels
|
||||
if userLevelStateMap[student][level] === 'complete'
|
||||
span.progress-level-cell.progress-level-cell-complete(style="width:#{levelCellWidth}%;") #{i + 1}
|
||||
.level-popup-container
|
||||
h3 #{i + 1}. #{level.replace('Course: ', '')}
|
||||
p
|
||||
- var playTime = Math.round(Math.random() * 600)
|
||||
span Time to solve
|
||||
span : #{moment.duration(playTime, "seconds").humanize()}
|
||||
p
|
||||
- var completionDate = new Date()
|
||||
- completionDate.setUTCDate(completionDate.getUTCDate() - Math.round(Math.random() * 60))
|
||||
span Completed on
|
||||
span : #{moment(completionDate).format('MMMM Do YYYY, h:mm:ss a')}
|
||||
strong(data-i18n="clans.view_solution") Click to view solution.
|
||||
else if userLevelStateMap[student][level] === 'started'
|
||||
span.progress-level-cell.progress-level-cell-started(style="width:#{levelCellWidth}%;") #{i + 1}
|
||||
.level-popup-container
|
||||
h3 #{i + 1}. #{level.replace('Course: ', '')}
|
||||
p
|
||||
- var completionDate = new Date()
|
||||
- completionDate.setUTCDate(completionDate.getUTCDate() - Math.round(Math.random() * 60))
|
||||
span Last played on
|
||||
span : #{moment(completionDate).format('MMMM Do YYYY, h:mm:ss a')}
|
||||
strong(data-i18n="clans.view_solution") Click to view solution.
|
||||
else
|
||||
break
|
||||
- i++
|
||||
|
||||
mixin levels-tab
|
||||
table.table.table-striped.table-condensed
|
||||
|
|
|
@ -37,7 +37,8 @@ module.exports = class CourseDetailsView extends RootView
|
|||
context.memberSort = @memberSort
|
||||
context.userConceptsMap = @userConceptsMap ? {}
|
||||
context.userLevelStateMap = @userLevelStateMap ? {}
|
||||
context.showExpandedProgress = @course.levels.length <= 30 or @showExpandedProgress
|
||||
context.showExpandedProgress = @showExpandedProgress
|
||||
context.stats = @stats
|
||||
context.studentMode = @options.studentMode ? false
|
||||
|
||||
conceptsCompleted = {}
|
||||
|
@ -46,15 +47,6 @@ module.exports = class CourseDetailsView extends RootView
|
|||
conceptsCompleted[concept] ?= 0
|
||||
conceptsCompleted[concept]++
|
||||
context.conceptsCompleted = conceptsCompleted
|
||||
|
||||
stats =
|
||||
averageLevelPlaytime: _.random(30, 240)
|
||||
averageLevelsCompleted: _.random(1, @course.levels.length)
|
||||
stats.totalPlayTime = context.instance.students?.length * stats.averageLevelPlaytime ? 0
|
||||
stats.totalLevelsCompleted = context.instance.students?.length * stats.averageLevelsCompleted ? 0
|
||||
stats.lastLevelCompleted = @course.levels[@maxLastStartedIndex] ? @course.levels[@course.levels.length - 1]
|
||||
context.stats = stats
|
||||
|
||||
context
|
||||
|
||||
initData: ->
|
||||
|
@ -73,6 +65,10 @@ module.exports = class CourseDetailsView extends RootView
|
|||
@levelMap = {}
|
||||
@levelMap[level] = true for level in @course.levels
|
||||
@userLevelStateMap = {}
|
||||
@stats =
|
||||
averageLevelPlaytime: _.random(30, 240)
|
||||
averageLevelsCompleted: _.random(1, @course.levels.length)
|
||||
students: {}
|
||||
@maxLastStartedIndex = -1
|
||||
for student in @instances?[@currentInstanceIndex].students
|
||||
@userLevelStateMap[student] = {}
|
||||
|
@ -82,7 +78,17 @@ module.exports = class CourseDetailsView extends RootView
|
|||
lastStartedIndex = lastCompletedIndex + 1
|
||||
@userLevelStateMap[student][@course.levels[lastStartedIndex]] = 'started'
|
||||
@maxLastStartedIndex = lastStartedIndex if lastStartedIndex > @maxLastStartedIndex
|
||||
|
||||
@stats[student] ?= {}
|
||||
@stats[student].levelsCompleted = 0
|
||||
@stats[student].levelsCompleted++ for level in @course.levels when @userLevelStateMap[student][level] is 'complete'
|
||||
@stats[student].secondsPlayed = Math.round(Math.random() * 1000 * (@stats[student].levelsCompleted + 1))
|
||||
@stats[student].secondsLastPlayed = Math.round(Math.random() * 100000)
|
||||
@sortMembers()
|
||||
@stats.totalPlayTime = @instances?[@currentInstanceIndex].students?.length * @stats.averageLevelPlaytime ? 0
|
||||
@stats.totalLevelsCompleted = @instances?[@currentInstanceIndex].students?.length * @stats.averageLevelsCompleted ? 0
|
||||
@stats.totalPlayTime = @instances?[@currentInstanceIndex].students?.length * @stats.averageLevelPlaytime ? 0
|
||||
@stats.lastLevelCompleted = @course.levels[0] ? @course.levels[@course.levels.length - 1]
|
||||
|
||||
sortMembers: ->
|
||||
# Progress sort precedence: most completed concepts, most started concepts, most levels, name sort
|
||||
|
@ -188,7 +194,7 @@ module.exports = class CourseDetailsView extends RootView
|
|||
container = $(e.target).find('.level-popup-container').show()
|
||||
margin = 20
|
||||
offset = $(e.target).offset()
|
||||
scrollTop = $(e.target).offsetParent().scrollTop()
|
||||
scrollTop = $('#page-container').scrollTop()
|
||||
height = container.outerHeight()
|
||||
container.css('left', offset.left + e.offsetX)
|
||||
container.css('top', offset.top + scrollTop - height - margin)
|
||||
|
|
Loading…
Reference in a new issue