Mark as done and progress updates
This commit is contained in:
parent
2a0901af02
commit
81d2edf0df
8 changed files with 257 additions and 89 deletions
|
|
@ -30,7 +30,6 @@ def get_notifications():
|
|||
"open_count_module": get_notifications_for_modules(config, notification_count),
|
||||
"open_count_other": get_notifications_for_other(config, notification_count),
|
||||
"targets": get_notifications_for_targets(config, notification_percent),
|
||||
"user_progress": get_user_progress_status(config),
|
||||
"new_messages": get_new_messages()
|
||||
}
|
||||
|
||||
|
|
@ -157,19 +156,6 @@ def get_notifications_for_targets(config, notification_percent):
|
|||
|
||||
return doc_target_percents
|
||||
|
||||
def get_user_progress_status(config):
|
||||
"User Progress status based on predefined setup slides"
|
||||
user_progress_status = {}
|
||||
for key, val in config.user_progress.iteritems():
|
||||
if "default" in val and val["default"] in frappe.defaults.get_defaults():
|
||||
doc_name = frappe.defaults.get_defaults()[val["default"]]
|
||||
field_value = frappe.db.get_value(val["doctype"], doc_name, val["field"])
|
||||
user_progress_status[key] = int(field_value > val["min_value"])
|
||||
elif "min_count" in val:
|
||||
user_progress_status[key] = int(frappe.db.count(val["doctype"]) > val["min_count"])
|
||||
|
||||
return user_progress_status
|
||||
|
||||
def clear_notifications(user=None):
|
||||
if frappe.flags.in_install:
|
||||
return
|
||||
|
|
@ -222,7 +208,7 @@ def get_notification_config():
|
|||
config = frappe._dict()
|
||||
for notification_config in frappe.get_hooks().notification_config:
|
||||
nc = frappe.get_attr(notification_config)()
|
||||
for key in ("for_doctype", "for_module", "for_other", "targets", "user_progress"):
|
||||
for key in ("for_doctype", "for_module", "for_other", "targets"):
|
||||
config.setdefault(key, {})
|
||||
config[key].update(nc.get(key, {}))
|
||||
return config
|
||||
|
|
|
|||
|
|
@ -15,3 +15,14 @@ def get_user_progress_slides():
|
|||
slides += frappe.get_attr(fn)()
|
||||
|
||||
return slides
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_and_get_user_progress():
|
||||
'''
|
||||
Return setup progress action states (called via `update_and_get_user_progress` hook)
|
||||
'''
|
||||
states = {}
|
||||
for fn in frappe.get_hooks('update_and_get_user_progress'):
|
||||
states.update(frappe.get_attr(fn)())
|
||||
|
||||
return states
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ fieldset[disabled] .form-control {
|
|||
}
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.video-modal {
|
||||
.video-modal .modal-dialog {
|
||||
width: 700px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1093,7 +1093,7 @@ input[type="checkbox"]:checked:before {
|
|||
cursor: pointer;
|
||||
}
|
||||
.slides-wrapper .form {
|
||||
margin-top: 15px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.slides-wrapper .form .form-layout {
|
||||
margin-top: 0px;
|
||||
|
|
@ -1121,6 +1121,12 @@ input[type="checkbox"]:checked:before {
|
|||
margin-top: 15px;
|
||||
padding: 0px 7px;
|
||||
}
|
||||
.slides-wrapper .footer .btn:not(:last-child) {
|
||||
margin-right: 3px;
|
||||
}
|
||||
.slides-wrapper .footer a.btn.make-btn {
|
||||
margin-right: 7px;
|
||||
}
|
||||
.slides-wrapper .footer a.make-btn.disabled {
|
||||
background-color: #b1bdca;
|
||||
color: #fff;
|
||||
|
|
@ -1132,6 +1138,7 @@ input[type="checkbox"]:checked:before {
|
|||
border: 1px solid #e5e5e5;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
.cards-container .card-container.done {
|
||||
background-color: #fafbfc;
|
||||
|
|
@ -1142,12 +1149,35 @@ input[type="checkbox"]:checked:before {
|
|||
.cards-container .card-container.single_action {
|
||||
cursor: pointer;
|
||||
}
|
||||
.cards-container .card-container.single_action .image-overlay {
|
||||
opacity: 0.1;
|
||||
}
|
||||
.cards-container .title {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.cards-container .content {
|
||||
font-size: 12px;
|
||||
}
|
||||
.cards-container .img-container {
|
||||
position: relative;
|
||||
}
|
||||
.cards-container .img-container .image-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
.cards-container .img-container .fa-play-circle {
|
||||
position: absolute;
|
||||
font-size: 42px;
|
||||
left: calc(33%);
|
||||
top: 25%;
|
||||
color: #fff;
|
||||
opacity: 0.8;
|
||||
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
.cards-container img {
|
||||
width: 195px;
|
||||
}
|
||||
|
|
@ -1157,11 +1187,34 @@ input[type="checkbox"]:checked:before {
|
|||
}
|
||||
.cards-container .content-container {
|
||||
padding: 10px;
|
||||
width: 516px;
|
||||
width: 92%;
|
||||
position: relative;
|
||||
}
|
||||
.cards-container .actions {
|
||||
.cards-container .action-area {
|
||||
margin-top: 15px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.cards-container .actions button:not(:first-child) {
|
||||
.cards-container .action-area button:not(:first-child),
|
||||
.cards-container .action-area a:not(:first-child) {
|
||||
margin-left: 15px;
|
||||
}
|
||||
.cards-container .check {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
right: 10px;
|
||||
top: calc(40%);
|
||||
}
|
||||
.user-progress-dialog .modal-title {
|
||||
display: inline-block;
|
||||
}
|
||||
.user-progress-dialog .progress-chart {
|
||||
display: inline-block;
|
||||
margin-left: 15px;
|
||||
width: 60px;
|
||||
}
|
||||
.user-progress-dialog .progress {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.user-progress-dialog .progress-bar {
|
||||
background-color: #98d85b;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ frappe.help.show_video = function(youtube_id, title) {
|
|||
frameborder="0" allowfullscreen></iframe>' + (frappe.help_feedback_link || ""),
|
||||
title || __("Help"));
|
||||
|
||||
dialog.$wrapper.find(".modal-content").addClass("video-modal");
|
||||
dialog.$wrapper.addClass("video-modal");
|
||||
}
|
||||
|
||||
$("body").on("click", "a.help-link", function() {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ frappe.ui.Slide = class Slide {
|
|||
</div>
|
||||
<div class="form-wrapper">
|
||||
<div class="form"></div>
|
||||
<div class="text-center" style="margin-top: 5px;">
|
||||
<div class="text-center" style="margin-top: 5px;margin-bottom: 30px;">
|
||||
<a class="form-more-btn hide btn btn-default btn-xs">${__("Add More")}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -33,7 +33,7 @@ frappe.ui.Slide = class Slide {
|
|||
|
||||
this.$content = this.$body.find(".content");
|
||||
this.$form = this.$body.find(".form");
|
||||
this.$primary_btn = this.slides_footer.find('.btn-primary').addClass('primary');
|
||||
this.$primary_btn = this.slides_footer.find('.primary');
|
||||
|
||||
if(this.help) this.$content.append($(`<p class="slide-help">${this.help}</p>`));
|
||||
if(this.image_src) this.$content.append(
|
||||
|
|
|
|||
|
|
@ -200,18 +200,6 @@ frappe.ui.toolbar.Toolbar = Class.extend({
|
|||
callback: function(r) {
|
||||
if(r.message) {
|
||||
let slides = r.message;
|
||||
let boot_info = frappe.boot.notification_info.user_progress;
|
||||
let completed = 0;
|
||||
slides.map(slide => {
|
||||
let key = slide.name;
|
||||
if(Object.keys(boot_info).includes(key) && boot_info[key]) {
|
||||
completed++;
|
||||
slide.done = 1;
|
||||
}
|
||||
});
|
||||
let percent = completed * 100 / slides.length;
|
||||
$('.user-progress .progress-bar').css({'width': percent + '%'});
|
||||
|
||||
frappe.require("assets/frappe/js/frappe/ui/toolbar/user_progress_dialog.js", function() {
|
||||
me.progress_dialog = new frappe.setup.UserProgressDialog({
|
||||
slides: slides
|
||||
|
|
|
|||
|
|
@ -18,35 +18,34 @@ frappe.ui.ActionCard = class {
|
|||
<div class="img-container">
|
||||
<img src="" class="clip">
|
||||
<div class="image-overlay hide"></div>
|
||||
<i class="play fa fa-fw fa-play-circle hide"></i>
|
||||
</div>
|
||||
<div class="content-container">
|
||||
<h5 class="title"></h5>
|
||||
<div class="content"></div>
|
||||
<div class="action-area">
|
||||
<div class="actions"></div>
|
||||
<div class="help-links"></div>
|
||||
</div>
|
||||
<i class="check pull-right fa fa-fw fa-check-circle text-success"
|
||||
style="font-size: 24px;"></i>
|
||||
<div class="action-area"></div>
|
||||
</div>
|
||||
<i class="check pull-right fa fa-fw fa-check-circle text-success"></i>
|
||||
</div>`);
|
||||
this.property_components = [
|
||||
{ card_property: 'content', component_name: '$content', class_name: 'content' },
|
||||
{ card_property: 'image', component_name: '$img_container', class_name: 'img-container'},
|
||||
{ card_property: 'done', component_name: '$check', class_name: 'check' },
|
||||
{ card_property: 'actions', component_name: '$actions', class_name: 'actions' },
|
||||
{ card_property: 'help_links', component_name: '$help_links', class_name: 'help-links' },
|
||||
{ card_properties: ['content'], component_name: '$content', class_name: 'content' },
|
||||
{ card_properties: ['image'], component_name: '$img_container', class_name: 'img-container'},
|
||||
{ card_properties: ['done'], component_name: '$check', class_name: 'check' },
|
||||
{ card_properties: ['actions', 'help_links'], component_name: '$action_area', class_name: 'action-area' }
|
||||
];
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.property_components.map(d => {
|
||||
this[d.component_name] = this.container.find('.' + d.class_name);
|
||||
if(!this[d.component_name]) {
|
||||
this[d.component_name] = this.container.find('.' + d.class_name);
|
||||
}
|
||||
});
|
||||
|
||||
if(this.data.video_id) {
|
||||
this.data.image = `http://img.youtube.com/vi/${this.data.video_id}/1.jpg`;
|
||||
this.data.image = `http://img.youtube.com/vi/${this.data.video_id}/0.jpg`;
|
||||
this.$img_container.find('.image-overlay').removeClass('hide');
|
||||
this.$img_container.find('.fa-play-circle').removeClass('hide');
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
|
|
@ -59,9 +58,13 @@ frappe.ui.ActionCard = class {
|
|||
|
||||
refresh() {
|
||||
// render according to props
|
||||
this.property_components.map(d => {
|
||||
if(!this.data[d.card_property]) {
|
||||
this[d.component_name].hide();
|
||||
this.property_components.map(comp => {
|
||||
let visible = 0;
|
||||
comp.card_properties.map(d => {
|
||||
if(this.data[d]) visible = 1;
|
||||
});
|
||||
if(!visible) {
|
||||
this[comp.component_name].hide();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -82,7 +85,7 @@ frappe.ui.ActionCard = class {
|
|||
if(this.data.actions) {
|
||||
this.data.actions.map(action => {
|
||||
let $btn = $(`<button class="btn btn-default btn-sm">${action.label}</button>`);
|
||||
this.$actions.append($btn);
|
||||
this.$action_area.append($btn);
|
||||
if(action.route) {
|
||||
$btn.on('click', () => {
|
||||
frappe.set_route(action.route);
|
||||
|
|
@ -97,7 +100,7 @@ frappe.ui.ActionCard = class {
|
|||
if(this.data.help_links) {
|
||||
this.data.help_links.map(link => {
|
||||
let $link = $(`<a target="_blank" href="${link.url}">${link.label}</a>`);
|
||||
this.$help_links.append($link);
|
||||
this.$action_area.append($link);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -127,8 +130,11 @@ frappe.setup.UserProgressSlide = class UserProgressSlide extends frappe.ui.Slide
|
|||
}
|
||||
|
||||
setup_done_state() {
|
||||
this.$body.find(".form-wrapper").hide();
|
||||
this.$body.find(".slide-help").hide();
|
||||
this.$body.find(".form-wrapper").hide();
|
||||
this.slides_footer.find('.next-btn').addClass('btn-primary');
|
||||
this.slides_footer.find('.done-btn').hide();
|
||||
this.$primary_btn.hide();
|
||||
this.make_action_cards();
|
||||
}
|
||||
|
||||
|
|
@ -154,8 +160,10 @@ frappe.setup.UserProgressSlide = class UserProgressSlide extends frappe.ui.Slide
|
|||
before_show() {
|
||||
if(this.done) {
|
||||
this.slides_footer.find('.next-btn').addClass('btn-primary');
|
||||
this.slides_footer.find('.done-btn').hide();
|
||||
} else {
|
||||
this.slides_footer.find('.next-btn').removeClass('btn-primary');
|
||||
this.slides_footer.find('.done-btn').show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,23 +171,16 @@ frappe.setup.UserProgressSlide = class UserProgressSlide extends frappe.ui.Slide
|
|||
var me = this;
|
||||
if(this.set_values()) {
|
||||
frappe.call({
|
||||
method: me.method,
|
||||
method: me.submit_method,
|
||||
args: {args_data: me.values},
|
||||
callback: function() {
|
||||
me.done = 1;
|
||||
// hide Create button immediately, or show_slide again
|
||||
me.slides_footer.find('.next-btn').addClass('btn-primary');
|
||||
me.$primary_btn.hide();
|
||||
me.refresh();
|
||||
},
|
||||
freeze: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mark_as_done() {
|
||||
// most hard
|
||||
}
|
||||
};
|
||||
|
||||
frappe.setup.UserProgressDialog = class UserProgressDialog {
|
||||
|
|
@ -187,47 +188,120 @@ frappe.setup.UserProgressDialog = class UserProgressDialog {
|
|||
slides = []
|
||||
}) {
|
||||
this.slides = slides;
|
||||
// Add a progress bar
|
||||
// show the last visited slide
|
||||
// Add a mark as done button
|
||||
// this.progress_state_dict = this.slides.map();
|
||||
|
||||
this.progress_state_dict = {};
|
||||
this.slides.map(slide => {
|
||||
this.progress_state_dict[slide.action_name] = slide.done || 0;
|
||||
});
|
||||
this.progress_percent = 0;
|
||||
this.setup();
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.dialog = new frappe.ui.Dialog({title: __("Complete Setup")});
|
||||
this.$wrapper = $(this.dialog.$wrapper).addClass('user-progress-dialog');
|
||||
this.$progress = $(`<div class="progress-chart">
|
||||
<div class="progress"><div class="progress-bar"></div></div>
|
||||
</div>`);
|
||||
this.dialog.header.find('.col-xs-7').append(this.$progress);
|
||||
this.slide_container = new frappe.ui.Slides({
|
||||
parent: this.dialog.body,
|
||||
slides: this.slides,
|
||||
slide_class: frappe.setup.UserProgressSlide,
|
||||
done_state: 1,
|
||||
before_load: ($footer) => {
|
||||
$footer.find('.text-right').prepend(
|
||||
$(`<a class="make-btn btn btn-primary btn-sm primary">
|
||||
${__("Create")}</a>`));
|
||||
$footer.find('.text-right')
|
||||
.prepend($(`<a class="done-btn btn btn-default btn-sm">
|
||||
${__("Mark as Done")}</a>`))
|
||||
.prepend($(`<a class="make-btn btn btn-primary btn-sm primary">
|
||||
${__("Create")}</a>`));
|
||||
},
|
||||
on_update: (completed, total) => {
|
||||
let percent = completed * 100 / total;
|
||||
this.$wrapper.find('.progress-bar').css({'width': percent + '%'});
|
||||
$('.user-progress .progress-bar').css({'width': percent + '%'});
|
||||
if(percent === 100) {
|
||||
$(document).trigger("user-initial-setup-complete");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.$wrapper.find('.done-btn').on('click', () => {
|
||||
this.mark_as_done();
|
||||
});
|
||||
|
||||
this.make_dismiss_button();
|
||||
this.get_and_update_progress_state();
|
||||
this.check_for_updates();
|
||||
}
|
||||
|
||||
listen_for_updates() {
|
||||
// on every notif 30 sec event
|
||||
this.update_progress_state();
|
||||
mark_as_done() {
|
||||
let me = this;
|
||||
let current_slide = this.slide_container.current_slide;
|
||||
frappe.call({
|
||||
method: current_slide.mark_as_done_method,
|
||||
args: {action_name: current_slide.action_name},
|
||||
callback: function() {
|
||||
current_slide.done = 1;
|
||||
current_slide.refresh();
|
||||
},
|
||||
freeze: true
|
||||
});
|
||||
}
|
||||
|
||||
update_progress_state() {
|
||||
// update states of slides and cards and refresh them
|
||||
// Update the progress bar in both the toolbar and the dialog
|
||||
check_for_updates() {
|
||||
this.updater = setInterval(() => {
|
||||
this.get_and_update_progress_state();
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
// remove on_update from original slides container
|
||||
get_and_update_progress_state() {
|
||||
var me = this;
|
||||
frappe.call({
|
||||
method: "frappe.desk.user_progress.update_and_get_user_progress",
|
||||
callback: function(r) {
|
||||
// console.log("states", r.message);
|
||||
let states = r.message;
|
||||
let changed = 0;
|
||||
let completed = 0;
|
||||
Object.keys(states).map(action_name => {
|
||||
if(states[action_name]) {
|
||||
completed ++;
|
||||
}
|
||||
if(me.progress_state_dict[action_name] != states[action_name]) {
|
||||
changed = 1;
|
||||
me.progress_state_dict[action_name] = states[action_name];
|
||||
}
|
||||
});
|
||||
|
||||
if(changed) {
|
||||
Object.keys(me.slide_container.slide_dict).map((id) => {
|
||||
let slide = me.slide_container.slide_dict[id];
|
||||
if(me.progress_state_dict[slide.action_name]) {
|
||||
if(!slide.done) {
|
||||
slide.done = 1;
|
||||
slide.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
me.progress_percent = completed / Object.keys(states).length * 100;
|
||||
me.update_progress();
|
||||
},
|
||||
freeze: false
|
||||
});
|
||||
}
|
||||
|
||||
update_progress() {
|
||||
this.update_progress_bars();
|
||||
}
|
||||
|
||||
update_progress_bars() {
|
||||
this.$wrapper.find('.progress-bar').css({'width': this.progress_percent + '%'});
|
||||
$('.user-progress .progress-bar').css({'width': this.progress_percent + '%'});
|
||||
if(this.progress_percent === 100) {
|
||||
$(document).trigger("user-initial-setup-complete");
|
||||
}
|
||||
}
|
||||
|
||||
make_dismiss_button() {
|
||||
|
|
@ -245,6 +319,7 @@ frappe.setup.UserProgressDialog = class UserProgressDialog {
|
|||
}
|
||||
|
||||
add_finish_slide_and_make_dismissable() {
|
||||
clearInterval(this.updater);
|
||||
this.$dismiss_button.removeClass('hide');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ textarea.form-control {
|
|||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.video-modal {
|
||||
.video-modal .modal-dialog {
|
||||
width: 700px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1036,7 +1036,7 @@ input[type="checkbox"] {
|
|||
}
|
||||
}
|
||||
.form {
|
||||
margin-top: 15px;
|
||||
margin-top: 30px;
|
||||
.form-layout {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
|
|
@ -1067,6 +1067,14 @@ input[type="checkbox"] {
|
|||
margin-top: 15px;
|
||||
padding: 0px 7px;
|
||||
|
||||
.btn:not(:last-child) {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
a.btn.make-btn {
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
a.make-btn.disabled {
|
||||
background-color: #b1bdca;
|
||||
color: #fff;
|
||||
|
|
@ -1083,6 +1091,7 @@ input[type="checkbox"] {
|
|||
border: 1px solid #e5e5e5;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
&.done {
|
||||
background-color: #fafbfc;
|
||||
|
|
@ -1094,12 +1103,12 @@ input[type="checkbox"] {
|
|||
|
||||
&.single_action {
|
||||
cursor: pointer;
|
||||
|
||||
// .title {
|
||||
// color: blue;
|
||||
.image-overlay {
|
||||
opacity: 0.1;
|
||||
}
|
||||
// .fa-play-circle{
|
||||
// opacity: 1;
|
||||
// }
|
||||
|
||||
// emphasize image overlay
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1110,9 +1119,28 @@ input[type="checkbox"] {
|
|||
.content {
|
||||
font-size: 12px;
|
||||
}
|
||||
// .img-container {
|
||||
.img-container {
|
||||
position: relative;
|
||||
|
||||
// }
|
||||
.image-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fa-play-circle {
|
||||
position: absolute;
|
||||
font-size: 42px;
|
||||
left: calc(50% - 17px);
|
||||
top: 25%;
|
||||
color: #fff;
|
||||
opacity: 0.8;
|
||||
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 195px;
|
||||
|
|
@ -1125,14 +1153,41 @@ input[type="checkbox"] {
|
|||
|
||||
.content-container {
|
||||
padding: 10px;
|
||||
width: 516px;
|
||||
width: 92%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.actions {
|
||||
.action-area {
|
||||
margin-top: 15px;
|
||||
font-size: 12px;
|
||||
|
||||
button:not(:first-child) {
|
||||
button:not(:first-child), a:not(:first-child) {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.check {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
right: 10px;
|
||||
top: calc(50% - 10px);
|
||||
}
|
||||
}
|
||||
|
||||
// User Progress Dialog
|
||||
.user-progress-dialog {
|
||||
.modal-title {
|
||||
display: inline-block;
|
||||
}
|
||||
.progress-chart {
|
||||
display: inline-block;
|
||||
margin-left: 15px;
|
||||
width: 60px;
|
||||
}
|
||||
.progress {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.progress-bar {
|
||||
background-color: #98d85b;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue