feat: move like to sidebar

This commit is contained in:
Ejaaz Khan 2025-12-18 00:53:01 +05:30
parent 9e72c10f62
commit fc09193fbd
7 changed files with 86 additions and 164 deletions

View file

@ -13,15 +13,6 @@ frappe.ui.form.ControlComment = class ControlComment extends frappe.ui.form.Cont
<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="icon icon-sm like-icon">
<use href="#icon-heart"></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,7 +7,6 @@ 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();
@ -65,40 +64,10 @@ frappe.ui.form.Footer = class FormFooter {
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, () => {
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

@ -34,9 +34,10 @@ frappe.ui.form.Sidebar = class {
this.setup_keyboard_shortcuts();
this.show_auto_repeat_status();
frappe.ui.form.setup_user_image_event(this.frm);
this.indicator = $(this.sidebar).find(".form-details .indicator-pill");
this.indicator = $(this.sidebar).find(".sidebar-meta-details .indicator-pill");
this.set_form_indicator();
this.setup_copy_event();
this.make_like();
this.refresh();
}
@ -77,16 +78,48 @@ frappe.ui.form.Sidebar = class {
this.refresh_creation_modified();
frappe.ui.form.set_user_image(this.frm);
}
this.refresh_like();
}
setup_copy_event() {
$(this.sidebar)
.find(".form-name-container .form-name-copy")
.find(".sidebar-meta-details .form-name-copy")
.on("click", (e) => {
frappe.utils.copy_to_clipboard($(e.currentTarget).attr("data-copy"));
});
}
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");
this.like_icon.on("click", () => {
frappe.ui.toggle_like(this.like_wrapper, this.frm.doctype, this.frm.doc.name, () => {
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);
console.log(liked, "wow", 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_web_view_count() {
if (this.frm.doc.route && cint(frappe.boot.website_tracking_enabled)) {
let route = this.frm.doc.route;
@ -100,62 +133,28 @@ frappe.ui.form.Sidebar = class {
}
refresh_creation_modified() {
let user_list = [this.frm.doc.owner, this.frm.doc.modified_by];
if (this.frm.doc.owner === this.frm.doc.modified_by) {
user_list = [this.frm.doc.owner];
}
let avatar_group = frappe.avatar_group(user_list, 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)])
) +
" · " +
cint(frappe.boot.user.show_absolute_datetime_in_timeline) ||
cint(frappe.boot.sysdefaults.show_absolute_datetime_in_timeline)
? frappe.datetime.str_to_user(this.frm.doc.creation)
: 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)])
) +
" · " +
cint(frappe.boot.user.show_absolute_datetime_in_timeline) ||
cint(frappe.boot.sysdefaults.show_absolute_datetime_in_timeline)
? frappe.datetime.str_to_user(this.frm.doc.modified)
: comment_when(this.frm.doc.modified);
if (user_list.length === 1) {
// same user created and edited
avatar_group.find(".avatar").popover({
trigger: "hover",
html: true,
content: creation_message + "<br>" + modified_message,
});
} else {
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,
});
}
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)
);
}
show_auto_repeat_status() {

View file

@ -1,5 +1,5 @@
<div class="sidebar-section user-actions hidden"></div>
<div class="sidebar-section sidebar-image-section hide">
<div class="flex justify-between sidebar-image-section sidebar-section hide">
<div class="sidebar-image-wrapper">
<img class="sidebar-image">
<div class="sidebar-standard-image">
@ -17,36 +17,23 @@
</div>
{% endif %}
</div>
<div class="form-stats-likes">
<span class="liked-by like-action d-flex align-items-center">
<svg class="icon icon-sm like-icon pointer">
<use href="#icon-heart"></use>
</svg>
<span class="like-count ml-2"></span>
</span>
</div>
</div>
<div class="sidebar-section sidebar-meta-details border-bottom">
<div class="form-details flex justify-between">
<span class="ellipsis mr-3">{%= frm.get_title() %}</span>
<span class="indicator-pill whitespace-nowrap"></span>
<span class="ellipsis mr-3 bold">{%= frm.get_title() %}</span>
<span class="form-name-copy" data-copy="{{frm.get_title()}}">{%= frappe.utils.icon("copy")%}</span>
</div>
<div class="form-name-container mt-2">
<div class="form-name-container mt-2 flex justify-between">
<span class="ellipsis mr-3">{%= frm.doc.name %}</span>
<span class="form-name-copy" data-copy="{{frm.doc.name}}">{%= frappe.utils.icon("copy")%}</span>
</div>
</div>
<div class="sidebar-section meta-section border-bottom">
<div class="created-by-wrapper">
<div class="created-by-label">
{%= frappe.utils.icon("user")%}
{%= __("Created By") %}
</div>
<div class="created-by-user">
{%= frappe.avatar(frappe.session.user, "avatar-xs")%}
{%= frappe.session.user %}
</div>
</div>
<div class="last-modified-wrapper">
<div class="last-modified-label">
{%= frappe.utils.icon("file-pen-line")%}
{%= __("Last Modified") %}
</div>
<div class="last-modified-time">
{%= frappe.datetime.prettyDate(cur_frm.doc.modified) %}
</div>
<span class="indicator-pill whitespace-nowrap"></span>
</div>
</div>
{% if frm.meta.beta %}
@ -77,8 +64,8 @@
<div>
<span class="form-sidebar-items">
<span class="add-assignment-label form-sidebar-label">
{%= frappe.utils.icon("user-plus") %}
<span class="ellipsis">{%= __("Assigned To") %}</span>
{%= frappe.utils.icon("users") %}
<span class="ellipsis">{%= __("Assign") %}</span>
</span>
<button class="add-assignment-btn btn btn-link icon-btn">
<svg class="es-icon icon-sm"><use href="#es-line-add"></use></svg>
@ -148,11 +135,14 @@
<div class="sidebar-section hidden">
<a><li class="indicator blue auto-repeat-status" style="display: none;"></li></a>
</div>
<!-- <div class="sidebar-section text-muted border-top mt-3 pt-3">
<div class="pageview-count hidden"></div>
<div class="created-modified-section">
</div>
</div> -->
<div class="sidebar-section text-muted border-top pt-3">
<ul class="list-unstyled sidebar-menu text-muted">
<li class="pageview-count"></li>
<li class="modified-by"></li>
<li class="created-by"></li>
</ul>
</div>
{% if(frappe.get_form_sidebar_extension) { %}
{{ frappe.get_form_sidebar_extension() }}
{% } %}

View file

@ -87,7 +87,7 @@ frappe.ui.setup_like_popover = ($parent, selector) => {
let liked_by_list = $(`<ul class="list-unstyled"></ul>`);
// to show social profile of the user
let link_base = "/app/user-profile/";
let link_base = "/desk/user/";
liked_by.forEach((user) => {
// append user list item

View file

@ -1,6 +1,6 @@
:root {
--form-sidebar-width: 277px;
--form-sidebar-image-width: 75px;
--form-sidebar-image-width: 80px;
}
.underline-hover {
display: initial;
@ -78,7 +78,6 @@
}
.sidebar-image-wrapper {
margin: auto;
position: relative;
width: fit-content;
height: fit-content;
@ -88,6 +87,7 @@
.sidebar-standard-image {
transition: opacity 0.3s;
width: var(--form-sidebar-image-width);
height: var(--form-sidebar-image-width);
border-radius: var(--border-radius-lg);
}
@ -123,36 +123,11 @@
align-items: center;
}
}
.form-name-container {
.sidebar-meta-details {
.form-name-copy {
cursor: pointer;
}
}
.meta-section {
display: flex;
flex-direction: column;
gap: 8px;
.created-by-wrapper,
.last-modified-wrapper {
display: flex;
justify-content: space-between;
gap: 12px;
}
.created-by-label,
.created-by-user,
.last-modified-label,
.last-modified-time {
display: flex;
padding: 6px 8px 6px 0px;
align-items: center;
gap: 8px;
flex: 0 0 50%;
svg {
margin: 0px;
}
}
}
}
.form-sidebar-label {
display: flex;
@ -160,7 +135,7 @@
gap: 8px;
}
body[data-route^="Form"] {
.layout-side-section {
.layout-side-section .form-sidebar {
width: var(--form-sidebar-width);
}
}
@ -374,7 +349,6 @@ body[data-route^="Form"] {
.add-assignment-btn,
.add-attachment-btn,
.add-review-btn,
.shares,
.add-tags-btn,
.share-doc-btn,
.followed-by {

View file

@ -56,7 +56,6 @@
.page-actions {
align-items: center;
overflow: auto;
.btn {
height: var(--btn-height);
margin-left: var(--margin-sm, 8px);
@ -95,7 +94,7 @@
body[data-route^="Form"] {
.layout-main-section-wrapper {
width: calc(100% - var(--form-sidebar-width));
flex: unset;
flex: calc(100% - var(--form-sidebar-width));
}
}