fix(styles): cleaner sidebars for list and form

This commit is contained in:
Rushabh Mehta 2024-08-13 12:53:44 +05:30
parent 2c7852e6aa
commit 1d678146a9
26 changed files with 418 additions and 273 deletions

View file

@ -652,6 +652,10 @@ def msgprint(
_raise_exception()
def toast(message: str, indicator: Literal["blue", "green", "orange", "red", "yellow"] | None = None):
frappe.msgprint(message, indicator=indicator, alert=True)
def clear_messages():
local.message_log = []

View file

@ -84,6 +84,7 @@
"default_app",
"updates_tab",
"system_updates_section",
"sidebar_position",
"disable_system_update_notification",
"disable_change_log_notification",
"backups_tab",
@ -611,7 +612,7 @@
{
"fieldname": "updates_tab",
"fieldtype": "Tab Break",
"label": "Updates"
"label": "Display"
},
{
"fieldname": "backups_tab",
@ -661,6 +662,7 @@
"label": "Store Attached PDF Document"
},
{
<<<<<<< HEAD
"fieldname": "app_tab",
"fieldtype": "Tab Break",
"label": "App"
@ -677,12 +679,23 @@
"fieldname": "rate_limit_email_link_login",
"fieldtype": "Int",
"label": "Rate limit for email link login"
=======
"default": "Left",
"fieldname": "sidebar_position",
"fieldtype": "Select",
"label": "Sidebar Position",
"options": "Left\nRight"
>>>>>>> 770a6df82a (fix(styles): cleaner sidebars for list and form)
}
],
"icon": "fa fa-cog",
"issingle": 1,
"links": [],
<<<<<<< HEAD
"modified": "2024-08-12 17:02:41.877346",
=======
"modified": "2024-08-09 11:55:19.592343",
>>>>>>> 770a6df82a (fix(styles): cleaner sidebars for list and form)
"modified_by": "Administrator",
"module": "Core",
"name": "System Settings",

View file

@ -83,12 +83,12 @@ class SystemSettings(Document):
]
otp_issuer_name: DF.Data | None
password_reset_limit: DF.Int
rate_limit_email_link_login: DF.Int
reset_password_link_expiry_duration: DF.Duration | None
reset_password_template: DF.Link | None
rounding_method: DF.Literal["Banker's Rounding (legacy)", "Banker's Rounding", "Commercial Rounding"]
session_expiry: DF.Data | None
setup_complete: DF.Check
sidebar_position: DF.Literal["Left", "Right"]
store_attached_pdf_document: DF.Check
strip_exif_metadata_from_uploaded_images: DF.Check
time_format: DF.Literal["HH:mm:ss", "HH:mm"]

View file

@ -42,19 +42,28 @@ def follow_document(doctype, doc_name, user):
)
or doctype in log_types
):
return
return False
if (not frappe.get_meta(doctype).track_changes) or user == "Administrator":
return
if not frappe.get_meta(doctype).track_changes:
frappe.toast(_("Can't follow since changes are not tracked."))
return False
if user == "Administrator":
frappe.toast(_("Administrator can't follow"))
return False
if not frappe.db.get_value("User", user, "document_follow_notify", ignore=True, cache=True):
return
frappe.toast(_("Document follow not set."))
return False
if not is_document_followed(doctype, doc_name, user):
doc = frappe.new_doc("Document Follow")
doc.update({"ref_doctype": doctype, "ref_docname": doc_name, "user": user})
doc.save()
return doc
frappe.toast(_("Following document {}".format(doc_name)))
return True
return False
@frappe.whitelist()
@ -67,8 +76,9 @@ def unfollow_document(doctype, doc_name, user):
)
if doc:
frappe.delete_doc("Document Follow", doc[0].name)
return 1
return 0
frappe.toast(_("Un-following document {}".format(doc_name)))
return False
return False
def get_message(doc_name, doctype, frequency, user):

View file

@ -9,7 +9,19 @@ frappe.ui.form.ControlComment = class ControlComment extends frappe.ui.form.Cont
? $(`
<div class="comment-input-wrapper">
<div class="comment-input-header">
<span>${__("Comments")}</span>
<div>
<span class="comment-title">${__("Comments")}</span>
<span class="comment-count"></span>
</div>
<div class="form-stats-likes">
<span class="liked-by like-action d-flex align-items-center">
<svg class="es-icon icon-sm">
<use href="#es-solid-heart" class="like-icon"></use>
</svg>
<span class="like-count ml-2"></span>
</span>
</div>
</div>
<div class="comment-input-container">
${frappe.avatar(frappe.session.user, "avatar-medium")}

View file

@ -7,6 +7,7 @@ frappe.ui.form.Footer = class FormFooter {
this.make();
this.make_comment_box();
this.make_timeline();
this.make_like();
// render-complete
$(this.frm.wrapper).on("render_complete", () => {
this.refresh();
@ -45,8 +46,8 @@ frappe.ui.form.Footer = class FormFooter {
this.frm.comment_box.set_value("");
frappe.utils.play_sound("click");
this.frm.timeline.add_timeline_item(comment_item);
this.frm.sidebar.refresh_comments_count &&
this.frm.sidebar.refresh_comments_count();
this.frm.get_docinfo().comments.push(comment);
this.refresh_comments_count();
})
.finally(() => {
this.frm.comment_box.enable();
@ -68,5 +69,46 @@ frappe.ui.form.Footer = class FormFooter {
this.parent.removeClass("hide");
this.frm.timeline.refresh();
}
this.refresh_comments_count();
this.refresh_like();
}
refresh_comments_count() {
let count = (this.frm.get_docinfo().comments || []).length;
this.wrapper.find(".comment-count")?.html(count ? `(${count})` : "");
}
make_like() {
this.like_wrapper = this.wrapper.find(".liked-by");
this.like_icon = this.wrapper.find(".liked-by .like-icon");
this.like_count = this.wrapper.find(".liked-by .like-count");
frappe.ui.setup_like_popover(this.wrapper.find(".form-stats-likes"), ".like-icon");
this.like_icon.on("click", () => {
frappe.ui.toggle_like(
this.like_wrapper,
this.frm.doctype,
this.frm.doc.name,
function () {
this.refresh_like();
}
);
});
}
refresh_like() {
if (!this.like_icon) {
return;
}
this.like_wrapper.attr("data-liked-by", this.frm.doc._liked_by);
const liked = frappe.ui.is_liked(this.frm.doc);
this.like_wrapper
.toggleClass("not-liked", !liked)
.toggleClass("liked", liked)
.attr("data-doctype", this.frm.doctype)
.attr("data-name", this.frm.doc.name);
this.like_count && this.like_count.text(JSON.parse(this.frm.doc._liked_by || "[]").length);
}
};

View file

@ -84,6 +84,7 @@ frappe.ui.form.Form = class FrappeForm {
frappe.ui.make_app_page({
parent: this.wrapper,
single_column: is_single_column,
sidebar_position: "Right",
});
this.page = this.wrapper.page;
this.layout_main = this.page.main.get(0);

View file

@ -87,11 +87,11 @@ frappe.ui.form.DocumentFollow = class DocumentFollow {
}
hide_follow_section() {
this.parent.hide();
this.parent.addClass("hidden");
}
set_followers() {
this.followed_by.removeClass("hidden");
this.parent.removeClass("hidden");
this.followed_by_label.removeClass("hidden");
this.followed_by.empty();
this.get_followed_user().then((user) => {

View file

@ -23,7 +23,6 @@ frappe.ui.form.Sidebar = class {
.html(sidebar_content)
.appendTo(this.page.sidebar.empty());
this.comments = this.sidebar.find(".form-sidebar-stats .comments");
this.user_actions = this.sidebar.find(".user-actions");
this.image_section = this.sidebar.find(".sidebar-image-section");
this.image_wrapper = this.image_section.find(".sidebar-image-wrapper");
@ -33,10 +32,7 @@ frappe.ui.form.Sidebar = class {
this.make_shared();
this.make_tags();
this.make_like();
this.make_follow();
this.bind_events();
this.setup_keyboard_shortcuts();
this.show_auto_repeat_status();
frappe.ui.form.setup_user_image_event(this.frm);
@ -44,21 +40,6 @@ frappe.ui.form.Sidebar = class {
this.refresh();
}
bind_events() {
var me = this;
// scroll to comments
this.comments.on("click", function () {
frappe.utils.scroll_to(me.frm.footer.wrapper.find(".comment-box"), true);
});
this.like_icon.on("click", function () {
frappe.ui.toggle_like(me.like_wrapper, me.frm.doctype, me.frm.doc.name, function () {
me.refresh_like();
});
});
}
setup_keyboard_shortcuts() {
// add assignment shortcut
let assignment_link = this.sidebar.find(".add-assignment");
@ -78,45 +59,62 @@ frappe.ui.form.Sidebar = class {
this.frm.tags && this.frm.tags.refresh(this.frm.get_docinfo().tags);
if (this.frm.doc.route && cint(frappe.boot.website_tracking_enabled)) {
let route = this.frm.doc.route;
frappe.utils.get_page_view_count(route).then((res) => {
this.sidebar
.find(".pageview-count")
.html(__("{0} Web page views", [String(res.message).bold()]));
});
}
this.sidebar
.find(".modified-by")
.html(
get_user_message(
this.frm.doc.modified_by,
__("You last edited this", null),
__("{0} last edited this", [get_user_link(this.frm.doc.modified_by)])
) +
" · " +
comment_when(this.frm.doc.modified)
);
this.sidebar
.find(".created-by")
.html(
get_user_message(
this.frm.doc.owner,
__("You created this", null),
__("{0} created this", [get_user_link(this.frm.doc.owner)])
) +
" · " +
comment_when(this.frm.doc.creation)
);
this.refresh_like();
this.refresh_follow();
this.refresh_comments_count();
this.refresh_web_view_count();
this.refresh_creation_modified();
frappe.ui.form.set_user_image(this.frm);
}
}
refresh_web_view_count() {
if (this.frm.doc.route && cint(frappe.boot.website_tracking_enabled)) {
let route = this.frm.doc.route;
frappe.utils.get_page_view_count(route).then((res) => {
this.sidebar
.find(".pageview-count")
.html(__("{0} Web page views", [String(res.message).bold()]));
});
}
}
refresh_creation_modified() {
let avatar_group = frappe.avatar_group([this.frm.doc.owner, this.frm.doc.modified_by], 5, {
align: "left",
overlap: true,
});
this.sidebar.find(".created-modified-section").append(avatar_group);
let creation_message =
get_user_message(
this.frm.doc.owner,
__("You created this", null),
__("{0} created this", [get_user_link(this.frm.doc.owner)])
) +
" · " +
comment_when(this.frm.doc.creation);
let modified_message =
get_user_message(
this.frm.doc.modified_by,
__("You last edited this", null),
__("{0} last edited this", [get_user_link(this.frm.doc.modified_by)])
) +
" · " +
comment_when(this.frm.doc.modified);
avatar_group.find(".avatar:first-child").popover({
trigger: "hover",
html: true,
content: creation_message,
});
avatar_group.find(".avatar:last-child").popover({
trigger: "hover",
html: true,
content: modified_message,
});
}
show_auto_repeat_status() {
if (this.frm.meta.allow_auto_repeat && this.frm.doc.auto_repeat) {
const me = this;
@ -195,64 +193,6 @@ frappe.ui.form.Sidebar = class {
this.user_actions.find(".user-action-row").remove();
}
make_like() {
this.like_wrapper = this.sidebar.find(".liked-by");
this.like_icon = this.sidebar.find(".liked-by .like-icon");
this.like_count = this.sidebar.find(".liked-by .like-count");
frappe.ui.setup_like_popover(this.sidebar.find(".form-stats-likes"), ".like-icon");
}
make_follow() {
this.follow_button = this.sidebar.find(".form-sidebar-stats .form-follow");
this.follow_button.on("click", () => {
let is_followed = this.frm.get_docinfo().is_document_followed;
frappe
.call("frappe.desk.form.document_follow.update_follow", {
doctype: this.frm.doctype,
doc_name: this.frm.doc.name,
following: !is_followed,
})
.then(() => {
frappe.model.set_docinfo(
this.frm.doctype,
this.frm.doc.name,
"is_document_followed",
!is_followed
);
this.refresh_follow(!is_followed);
});
});
}
refresh_follow(follow) {
if (follow == null) {
follow = this.frm.get_docinfo().is_document_followed;
}
this.follow_button.text(follow ? __("Unfollow") : __("Follow"));
}
refresh_like() {
if (!this.like_icon) {
return;
}
this.like_wrapper.attr("data-liked-by", this.frm.doc._liked_by);
const liked = frappe.ui.is_liked(this.frm.doc);
this.like_wrapper
.toggleClass("not-liked", !liked)
.toggleClass("liked", liked)
.attr("data-doctype", this.frm.doctype)
.attr("data-name", this.frm.doc.name);
this.like_count && this.like_count.text(JSON.parse(this.frm.doc._liked_by || "[]").length);
}
refresh_comments_count() {
let count = (this.frm.get_docinfo().comments || []).length;
this.comments.find(".comments-count").html(count);
}
refresh_image() {}
make_review() {

View file

@ -116,8 +116,8 @@
<div class="shares"></div>
</li>
</ul>
<ul class="list-unstyled sidebar-menu followed-by-section">
<li class="sidebar-label followed-by-label hidden">
<ul class="list-unstyled sidebar-menu followed-by-section hidden">
<li class="sidebar-label followed-by-label">
<svg class="icon icon-sm">
<use href="#icon-link-url" class="like-icon"></use>
</svg>
@ -136,35 +136,10 @@
<ul class="list-unstyled sidebar-menu">
<a><li class="auto-repeat-status"><li></a>
</ul>
<ul class="list-unstyled sidebar-menu form-sidebar-stats">
<li class="flex">
<div class="form-stats d-flex">
<span class="form-stats-likes">
<span class="liked-by like-action d-flex align-items-center">
<svg class="es-icon icon-sm">
<use href="#es-solid-heart" class="like-icon"></use>
</svg>
<span class="like-count ml-2"></span>
</span>
</span>
<span class="mx-2">·</span>
<a class="comments d-flex align-items-center">
<svg class="es-icon icon-sm">
<use href="#es-line-chat-alt" class="comment-icon"></use>
</svg>
<span class="comments-count ml-2"></span>
</a>
</div>
<a class="form-follow text-sm">
Follow
</a>
</li>
</ul>
<hr>
<ul class="list-unstyled sidebar-menu text-muted">
<li class="pageview-count"></li>
<li class="modified-by"></li>
<li class="created-by"></li>
<li class="created-modified-section">
</li>
</ul>
{% if(frappe.get_form_sidebar_extension) { %}
{{ frappe.get_form_sidebar_extension() }}

View file

@ -17,6 +17,7 @@ frappe.ui.form.Toolbar = class Toolbar {
this.page.clear_user_actions();
this.show_title_as_dirty();
this.set_primary_action();
this.refresh_follow();
if (this.frm.meta.hide_toolbar) {
this.page.hide_menu();
@ -273,85 +274,87 @@ frappe.ui.form.Toolbar = class Toolbar {
this.page.clear_menu();
if (frappe.boot.desk_settings.form_sidebar) {
this.make_navigation();
// this.make_navigation();
this.make_menu_items();
}
}
make_navigation() {
// Navigate
if (!this.frm.is_new() && !this.frm.meta.issingle) {
this.page.add_action_icon(
"es-line-left-chevron",
() => {
this.frm.navigate_records(1);
},
"prev-doc",
__("Previous Document")
);
this.page.add_action_icon(
"es-line-right-chevron",
() => {
this.frm.navigate_records(0);
},
"next-doc",
__("Next Document")
);
}
}
make_menu_items() {
// Print
const me = this;
const p = this.frm.perm[0];
const docstatus = cint(this.frm.doc.docstatus);
const is_submittable = frappe.model.is_submittable(this.frm.doc.doctype);
this.add_discard();
this.add_print();
this.add_email();
this.add_rename();
this.add_reload();
this.add_delete();
this.add_duplicate();
this.add_new();
this.page.add_divider();
this.add_audit_trail();
this.add_jump_to_field();
this.add_show_links();
this.add_remind_me();
this.add_follow();
this.add_undo_redo();
this.add_auto_repeat();
this.page.add_divider();
this.make_customize_buttons();
}
const print_settings = frappe.model.get_doc(":Print Settings", "Print Settings");
const allow_print_for_draft = cint(print_settings.allow_print_for_draft);
const allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled);
if (is_submittable && docstatus == 0 && !this.has_workflow()) {
add_discard() {
if (
frappe.model.is_submittable(this.frm.doc.doctype) &&
this.frm.doc.docstatus == 0 &&
!this.has_workflow()
) {
this.page.add_menu_item(
__("Discard"),
function () {
me.frm._discard();
this.frm._discard();
},
true
);
}
}
add_print() {
const print_settings = frappe.model.get_doc(":Print Settings", "Print Settings");
const allow_print_for_draft = cint(print_settings.allow_print_for_draft);
const allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled);
if (
!is_submittable ||
docstatus == 1 ||
(allow_print_for_cancelled && docstatus == 2) ||
(allow_print_for_draft && docstatus == 0)
!frappe.model.is_submittable(this.frm.doc.doctype) ||
this.frm.doc.docstatus == 1 ||
(allow_print_for_cancelled && this.frm.doc.docstatus == 2) ||
(allow_print_for_draft && this.frm.doc.docstatus == 0)
) {
if (frappe.model.can_print(null, me.frm) && !this.frm.meta.issingle) {
if (frappe.model.can_print(null, this.frm) && !this.frm.meta.issingle) {
this.page.add_menu_item(
__("Print"),
function () {
me.frm.print_doc();
() => {
this.frm.print_doc();
},
true
);
this.print_icon = this.page.add_action_icon(
"printer",
function () {
me.frm.print_doc();
() => {
this.frm.print_doc();
},
"",
__("Print")
);
}
}
}
add_email() {
// email
if (frappe.model.can_email(null, me.frm) && me.frm.doc.docstatus < 2) {
if (frappe.model.can_email(null, this.frm) && this.frm.doc.docstatus < 2) {
this.page.add_menu_item(
__("Email"),
function () {
me.frm.email_doc();
() => {
this.frm.email_doc();
},
true,
{
@ -360,80 +363,80 @@ frappe.ui.form.Toolbar = class Toolbar {
}
);
}
}
add_jump_to_field() {
// go to field modal
this.page.add_menu_item(
__("Jump to field"),
function () {
me.show_jump_to_field_dialog();
() => {
this.show_jump_to_field_dialog();
},
true,
"Ctrl+J"
);
}
// Linked With
if (!me.frm.meta.issingle) {
add_show_links() {
if (!this.frm.meta.issingle) {
this.page.add_menu_item(
__("Links"),
function () {
me.show_linked_with();
__("Show Links"),
() => {
this.show_linked_with();
},
true
);
}
}
// duplicate
if (frappe.boot.user.can_create.includes(me.frm.doctype) && !me.frm.meta.allow_copy) {
add_duplicate() {
if (frappe.boot.user.can_create.includes(this.frm.doctype) && !this.frm.meta.allow_copy) {
this.page.add_menu_item(
__("Duplicate"),
function () {
me.frm.copy_doc();
() => {
this.frm.copy_doc();
},
true,
"Shift+D"
);
}
}
// copy doc to clipboard
this.page.add_menu_item(
__("Copy to Clipboard"),
function () {
frappe.utils.copy_to_clipboard(JSON.stringify(me.frm.doc));
},
true
);
// rename
add_rename() {
if (this.can_rename()) {
this.page.add_menu_item(
__("Rename"),
function () {
me.frm.rename_doc();
() => {
this.frm.rename_doc();
},
true
);
}
}
add_reload() {
// reload
this.page.add_menu_item(
__("Reload"),
function () {
me.frm.reload_doc();
() => {
this.frm.reload_doc();
},
true
);
}
add_delete() {
// delete
if (
cint(me.frm.doc.docstatus) != 1 &&
!me.frm.doc.__islocal &&
!frappe.model.is_single(me.frm.doctype) &&
frappe.model.can_delete(me.frm.doctype)
cint(this.frm.doc.docstatus) != 1 &&
!this.frm.doc.__islocal &&
!frappe.model.is_single(this.frm.doctype) &&
frappe.model.can_delete(this.frm.doctype)
) {
this.page.add_menu_item(
__("Delete"),
function () {
me.frm.savetrash();
() => {
this.frm.savetrash();
},
true,
{
@ -442,7 +445,9 @@ frappe.ui.form.Toolbar = class Toolbar {
}
);
}
}
add_remind_me() {
this.page.add_menu_item(
__("Remind Me"),
() => {
@ -455,7 +460,21 @@ frappe.ui.form.Toolbar = class Toolbar {
condition: () => !this.frm.is_new(),
}
);
//
}
add_follow() {
if (this.frm.meta.track_changes && frappe.boot.user.document_follow_notify) {
this.follow_menu_item = this.page.add_menu_item(
__(this.get_follow_text()),
() => {
this.follow();
},
true
);
}
}
add_undo_redo() {
// Undo and redo
this.page.add_menu_item(
__("Undo"),
@ -481,26 +500,29 @@ frappe.ui.form.Toolbar = class Toolbar {
description: __("Redo last action"),
}
);
}
this.make_customize_buttons();
add_auto_repeat() {
// Auto Repeat
if (this.can_repeat()) {
this.page.add_menu_item(
__("Repeat"),
function () {
frappe.utils.new_auto_repeat_prompt(me.frm);
() => {
frappe.utils.new_auto_repeat_prompt(this.frm);
},
true
);
}
}
add_new() {
let p = this.frm.perm[0];
// New
if (p[CREATE] && !this.frm.meta.issingle && !this.frm.meta.in_create) {
this.page.add_menu_item(
__("New {0}", [__(me.frm.doctype)]),
function () {
frappe.new_doc(me.frm.doctype, true);
__("New {0}", [__(this.frm.doctype)]),
() => {
frappe.new_doc(this.frm.doctype, true);
},
true,
{
@ -509,14 +531,16 @@ frappe.ui.form.Toolbar = class Toolbar {
}
);
}
}
add_audit_trail() {
if (
this.frm.doc.amended_from &&
frappe.model.get_value("DocType", this.frm.doc.doctype, "track_changes")
) {
this.page.add_menu_item(
__("View Audit Trail"),
function () {
() => {
frappe.set_route("audit-trail");
},
true
@ -783,4 +807,36 @@ frappe.ui.form.Toolbar = class Toolbar {
dialog.show();
}
follow() {
let is_followed = this.frm.get_docinfo().is_document_followed;
frappe
.call("frappe.desk.form.document_follow.update_follow", {
doctype: this.frm.doctype,
doc_name: this.frm.doc.name,
following: !is_followed,
})
.then((r) => {
is_followed = r.message ? true : false;
frappe.model.set_docinfo(
this.frm.doctype,
this.frm.doc.name,
"is_document_followed",
is_followed
);
this.refresh_follow(is_followed);
});
}
get_follow_text(follow) {
if (follow === null) {
follow = this.frm.get_docinfo().is_document_followed;
}
return follow ? __("Unfollow") : __("Follow");
}
refresh_follow(follow) {
this.follow_menu_item?.text(this.get_follow_text(follow));
}
};

View file

@ -29,7 +29,7 @@ frappe.views.ListFactory = class ListFactory extends frappe.views.Factory {
frappe.views.list_view[me.page_name] = new view_class({
doctype: doctype,
parent: me.make_page(true, me.page_name),
parent: me.make_page(true, me.page_name, "Right"),
});
me.set_cur_list();

View file

@ -56,9 +56,16 @@ export default class ListFilter {
refresh() {
this.get_list_filters().then(() => {
this.filters.length
? this.$saved_filters_preview.show()
: this.$saved_filters_preview.hide();
if (this.filters.length) {
// expand collapsible sections
this.wrapper.hasClass("hide") && this.section_title.trigger("click");
this.$saved_filters_preview.show();
} else {
// hide collapsible sections
!this.wrapper.hasClass("hide") && this.section_title.trigger("click");
this.$saved_filters_preview.hide();
}
const html = this.filters.map((filter) => this.filter_template(filter));
this.wrapper.find(".filter-pill").remove();
this.$saved_filters.append(html);

View file

@ -38,7 +38,17 @@
<div class="list-group-by">
</div>
<div class="list-tags">
</div>
<div class="sidebar-section tags-section">
<li class="sidebar-label">
<svg class="es-icon es-line icon-xs" aria-hidden="true">
<use class="" href="#es-line-right-chevron"></use>
</svg>
<span>{{ __("Tags") }}</span>
</li>
<div class="list-tags hide">
<li class="list-stats list-link">
<a
class="btn btn-default btn-sm list-sidebar-button"
@ -62,15 +72,20 @@
</div>
</ul>
</li>
<li class="sidebar-action show-tags">
<a class="list-tag-preview">{{ __("Show Tags") }}</a>
<li class="sidebar-label">
<li class="sidebar-action show-tags">
<a class="list-tag-preview">{{ __("Show Tags") }}</a>
</li>
</li>
</div>
</div>
<div class="sidebar-section save-filter-section">
<li class="sidebar-label">
{{ __("Save Filter") }}
<svg class="es-icon es-line icon-xs" aria-hidden="true">
<use class="" href="#es-line-right-chevron"></use>
</svg>
<span>{{ __("Saved Filters") }}</span>
</li>
<li class="list-filters list-link"></li>
<li class="list-filters list-link hide"></li>
</ul>

View file

@ -23,6 +23,7 @@ frappe.views.ListSidebar = class ListSidebar {
this.setup_list_filter();
this.setup_list_group_by();
this.setup_collapsible();
// do not remove
// used to trigger custom scripts
@ -164,9 +165,30 @@ frappe.views.ListSidebar = class ListSidebar {
wrapper: this.page.sidebar.find(".list-filters"),
doctype: this.doctype,
list_view: this.list_view,
section_title: this.page.sidebar.find(".save-filter-section .sidebar-label"),
});
}
setup_collapsible() {
// tags and save filter sections should be collapsible
let sections = [
["tags-section", "list-tags"],
["save-filter-section", "list-filters"],
];
for (let s of sections) {
this.page.sidebar.find(`.${s[0]} .sidebar-label`).on("click", () => {
let list_tags = this.page.sidebar.find("." + s[1]);
let icon = "#es-line-down";
list_tags.toggleClass("hide");
if (list_tags.hasClass("hide")) {
icon = "#es-line-right-chevron";
}
this.page.sidebar.find(`.${s[0]} .es-line use`).attr("href", icon);
});
}
}
setup_kanban_boards() {
const $dropdown = this.page.sidebar.find(".kanban-dropdown");
frappe.views.KanbanView.setup_dropdown_in_sidebar(this.doctype, $dropdown);

View file

@ -8,6 +8,7 @@
*
* @param {string} opts.parent [HTMLElement] Parent element
* @param {boolean} opts.single_column Whether to include sidebar
* @param {string} [opts.sidebar_position] Position of sidebar (default None, "Left" or "Right")
* @param {string} [opts.title] Page title
* @param {Object} [opts.make_page]
*
@ -106,6 +107,13 @@ frappe.ui.Page = class Page {
</div>
`
);
if (this.sidebar_position === "Right") {
this.wrapper
.find(".layout-main-section-wrapper")
.insertBefore(this.wrapper.find(".layout-side-section"));
this.wrapper.find(".layout-side-section").addClass("right");
}
}
this.setup_page();
@ -509,7 +517,7 @@ frappe.ui.Page = class Page {
if (standard) {
$li.appendTo(parent);
} else {
this.divider = parent.find(".dropdown-divider");
this.divider = parent.find(".dropdown-divider.user-action");
if (!this.divider.length) {
this.divider = $('<li class="dropdown-divider user-action"></li>').prependTo(
parent
@ -647,6 +655,7 @@ frappe.ui.Page = class Page {
let response = action();
me.btn_disable_enable(btn, response);
};
// Add actions as menu item in Mobile View
let menu_item_label = group ? `${group} > ${label}` : label;
let menu_item = this.add_menu_item(menu_item_label, _action, false, false, false);

View file

@ -29,12 +29,12 @@ frappe.views.Factory = class Factory {
}
}
make_page(double_column, page_name) {
return frappe.make_page(double_column, page_name);
make_page(double_column, page_name, sidebar_postition) {
return frappe.make_page(double_column, page_name, sidebar_postition);
}
};
frappe.make_page = function (double_column, page_name) {
frappe.make_page = function (double_column, page_name, sidebar_position) {
if (!page_name) {
page_name = frappe.get_route_str();
}
@ -44,6 +44,7 @@ frappe.make_page = function (double_column, page_name) {
frappe.ui.make_app_page({
parent: page,
single_column: !double_column,
sidebar_position: sidebar_position,
});
frappe.container.change_to(page_name);

View file

@ -121,7 +121,6 @@ export default class Onboarding extends Block {
this.add_settings_button();
this.add_new_block_button();
}
$(this.wrapper).css("padding-bottom", "20px");
return this.wrapper;
}

View file

@ -79,7 +79,8 @@ $disabled-input-height: 22px;
--fg-color: white;
--subtle-accent: var(--gray-50);
--subtle-fg: var(--gray-100);
--navbar-bg: white;
--navbar-bg: var(--gray-50);
// --navbar-bg: white;
--fg-hover-color: var(--gray-100);
--card-bg: var(--fg-color);
--disabled-text-color: var(--gray-600);

View file

@ -27,7 +27,7 @@ $check-icon-dark: url("data:image/svg+xml, <svg viewBox='0 0 8 7' fill='none' xm
--fg-color: var(--gray-900);
--subtle-accent: var(--gray-700);
--subtle-fg: var(--gray-800);
--navbar-bg: var(--gray-900);
--navbar-bg: var(--gray-800);
--fg-hover-color: var(--gray-800);
--card-bg: var(--gray-900);
--disabled-text-color: var(--gray-400);

View file

@ -16,6 +16,10 @@ body {
cursor: pointer;
margin-bottom: var(--margin-xs) !important;
.section-title {
margin-left: 4px;
}
span {
pointer-events: none;
}
@ -347,7 +351,9 @@ body {
}
&.onboarding-widget-box {
margin-bottom: var(--margin-2xl);
margin: 0 -15px;
padding: 0 15px;
padding-bottom: 30px;
background-color: var(--bg-color);
border-bottom: 1px solid var(--border-color);
border-radius: 0;
@ -421,7 +427,9 @@ body {
.onboarding-step-body {
color: var(--text-muted);
p {
p,
li {
line-height: 1.6;
@include get_textstyle("base", "regular");
}
}
@ -986,6 +994,7 @@ body {
.layout-main-section {
border: 1px solid var(--border-color);
border-top: 0px;
padding: var(--padding-md);
margin-bottom: var(--margin-sm);
@ -1015,7 +1024,6 @@ body {
.layout-main-section {
background-color: var(--fg-color);
box-shadow: none;
border-radius: var(--border-radius-lg);
padding: var(--padding-sm);
}
@ -1059,6 +1067,7 @@ body {
svg {
margin-right: 0;
margin-top: -3px;
}
.dropdown-list {

View file

@ -23,8 +23,8 @@
}
.std-form-layout > .form-layout > .form-page {
border-radius: var(--border-radius-md);
border: 1px solid var(--border-color);
border-top: 0px;
box-shadow: none;
background-color: var(--card-bg);
}
@ -145,7 +145,22 @@
margin-top: var(--margin-lg);
padding: 0;
.comment-input-header {
@extend .head-title;
display: flex;
justify-content: space-between;
.comment-title {
@extend .head-title;
}
.comment-count {
margin-left: 5px;
color: var(--text-light);
}
.form-stat-likes {
display: flex;
vertical-align: middle;
}
margin-bottom: var(--margin-sm);
}
.comment-input-container {
@ -305,10 +320,8 @@
.form-message {
position: relative;
border-radius: var(--border-radius);
padding: 8px 10px;
font-size: var(--text-md, 13px);
margin-bottom: var(--margin-md);
&.blue {
@include form-message-background("blue");

View file

@ -93,6 +93,8 @@
@include card($padding: 0px);
box-shadow: none;
border: 1px solid var(--border-color);
border-top: 0px;
border-radius: 0px;
}
.page-head {
@ -100,7 +102,7 @@
position: sticky;
top: var(--navbar-height);
background: var(--bg-color);
margin-bottom: 5px;
border-bottom: 1px solid var(--border-color);
transition: 0.5s top;
.page-head-content {
height: var(--page-head-height);

View file

@ -113,11 +113,6 @@ body[data-route^="Module"] .main-menu {
li:first-child {
@include flex(flex, space-between, center, null);
.form-follow {
text-transform: uppercase;
font-size: var(--text-xs, 11px);
}
use.comment-icon {
fill: var(--gray-500);
}
@ -125,13 +120,13 @@ body[data-route^="Module"] .main-menu {
}
.sidebar-image-section {
width: min(100%, 170px);
width: min(100%, 200px);
cursor: pointer;
border-radius: var(--border-radius-lg);
.sidebar-image {
height: auto;
max-height: 170px;
max-height: 200px;
object-fit: cover;
}
@ -182,7 +177,14 @@ body[data-route^="Module"] .main-menu {
.layout-side-section {
@include get_textstyle("sm", "regular");
padding-right: 30px;
// padding-right: 30px;
padding-top: 15px;
padding-right: 5px;
&.right {
padding-left: 5px;
padding-right: 15px;
}
&.hide-sidebar {
display: none;
@ -205,9 +207,16 @@ body[data-route^="Module"] .main-menu {
font-size: var(--text-xs);
font-weight: var(--weight-regular);
margin-bottom: var(--margin-sm);
text-transform: uppercase;
display: flex;
align-items: center;
color: var(--text-muted);
cursor: pointer;
.es-icon {
margin-right: 4px;
}
.icon {
margin: 0;
margin-right: var(--margin-xs);
@ -301,6 +310,10 @@ body[data-route^="Module"] .main-menu {
.list-sidebar {
.sidebar-section {
margin-bottom: 30px;
a {
font-size: var(--text-xs);
}
}
.list-link {

View file

@ -8,7 +8,7 @@
--text-xs: 12px;
--text-sm: 13px;
--text-md: 13px; // alias
--text-base: 14px;
--text-base: 13px;
--text-lg: 16px;
--text-xl: 18px;
--text-2xl: 20px;

View file

@ -141,6 +141,7 @@ ignore = [
"F722", # syntax error in forward type annotation
"W191", # indentation contains tabs
"RUF001", # string contains ambiguous unicode character
"UP032", # Use f-string instead of `format` call
]
typing-modules = ["frappe.types.DF"]