`);
- this.$frappe_list.append(this.$result);
+ this.$frappe_list.find(".result-container").append(this.$result);
}
setup_no_result_area() {
diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js
index 9a02eb753c..64cc2a6c39 100644
--- a/frappe/public/js/frappe/list/list_view.js
+++ b/frappe/public/js/frappe/list/list_view.js
@@ -33,6 +33,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
);
this.count_upper_bound = 1001;
this._element_factory = new ElementFactory(this.doctype);
+ this.column_max_widths = {};
}
has_permissions() {
@@ -633,14 +634,27 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
this.$result.find(".list-row-container").remove();
this.render_header();
+ let has_assignto = false;
+
if (this.data.length > 0) {
// append rows
let idx = 0;
for (let doc of this.data) {
doc._idx = idx++;
this.$result.append(this.get_list_row_html(doc));
+ if (!has_assignto && doc._assign) {
+ has_assignto = true;
+ }
}
}
+ this.apply_column_widths();
+
+ // add class to result to indetify that it has assignto
+ if (has_assignto) {
+ this.$result.addClass("has-assign-to");
+ } else {
+ this.$result.addClass("no-assign-to");
+ }
}
render_count() {
@@ -703,6 +717,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
col.type == "Subject" ? "list-subject level" : "hidden-xs",
col.type == "Tag" ? "tag-col hide" : "",
frappe.model.is_numeric_field(col.df) ? "text-right" : "",
+ col.df?.fieldname,
].join(" ");
let html = "";
@@ -767,7 +782,22 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
}
get_left_html(doc) {
- let left_html = this.columns.map((col) => this.get_column_html(col, doc)).join("");
+ // let left_html = this.columns.map((col) => this.get_column_html(col, doc)).join("");
+
+ let left_html = "";
+ for (let i = 0; i < this.columns.length; i++) {
+ let col = this.columns[i];
+
+ if (frappe.is_mobile() && col.type == "Field" && [3, 4].includes(i)) {
+ left_html += `
${this.get_column_html(
+ col,
+ doc,
+ true
+ )}
`;
+ } else {
+ left_html += this.get_column_html(col, doc, false);
+ }
+ }
left_html += this.generate_button_html(doc);
left_html += this.generate_dropdown_html(doc);
@@ -798,7 +828,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
`;
}
- get_column_html(col, doc) {
+ get_column_html(col, doc, show_in_mobile) {
if (col.type === "Status" || col.df?.options == "Workflow State") {
let show_workflow_state = col.df?.options == "Workflow State";
return `
@@ -906,12 +936,13 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
const class_map = {
Subject: "list-subject level",
- Field: "hidden-xs",
+ Field: !show_in_mobile ? "hidden-xs" : "",
};
- const css_class = [
+ let css_class = [
"list-row-col ellipsis",
class_map[col.type],
frappe.model.is_numeric_field(df) ? "text-right" : "",
+ fieldname,
].join(" ");
let column_html;
@@ -928,6 +959,29 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
}[col.type];
}
+ if (frappe.is_mobile() && col.type == "Subject") {
+ css_class += " bold";
+ }
+
+ /**
+ * Calculates the width of a text element based on its length.
+ * If the length of the text is not available, it defaults to a length of 22.5.
+ */
+ let textLength = $(column_html).text()?.trim()?.length || 22.5;
+ let calculatedWidth = (textLength * 10) / 1.3;
+
+ /**
+ * Updates the `column_max_widths` object by setting the maximum width for a specific column (fieldname).
+ * If no width is set for the column, or the newly calculated width exceeds the current width, the width is updated.
+ */
+ if (
+ (!this.column_max_widths[fieldname] ||
+ calculatedWidth > this.column_max_widths[fieldname]) &&
+ !frappe.is_mobile()
+ ) {
+ this.column_max_widths[fieldname] = calculatedWidth;
+ }
+
return `
${column_html}
@@ -935,6 +989,20 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
`;
}
+ /**
+ * Applies dynamically calculated widths to elements based on their respective class names.
+ * Iterates through `column_max_widths` and sets the `width` and `flex` styles for each column.
+ * The width for each column is applied as both a fixed `width` and a flexible `flex` property.
+ */
+ apply_column_widths() {
+ Object.entries(this.column_max_widths).forEach(([fieldname, width]) => {
+ $(`.${fieldname}`).css({
+ width: width,
+ flex: `1 0 ${width}px`,
+ });
+ });
+ }
+
get_tags_html(user_tags, limit, colored = false) {
let get_tag_html = (tag) => {
let color = "",
diff --git a/frappe/public/scss/desk/list.scss b/frappe/public/scss/desk/list.scss
index 79e2fd9c45..77c04cec33 100644
--- a/frappe/public/scss/desk/list.scss
+++ b/frappe/public/scss/desk/list.scss
@@ -60,7 +60,6 @@
.list-row-container {
display: flex;
flex-direction: column;
- padding: var(--padding-xs) var(--padding-md);
border-bottom: 1px solid $border-color;
&:focus {
@@ -73,15 +72,26 @@
padding-top: 0;
border-bottom: none;
}
+}
- &:last-child {
- border-bottom: none;
+.frappe-list {
+ margin: var(--margin-xs) var(--margin-md);
+ .result.has-assign-to {
+ .list-row .level-right {
+ flex: 0 0 180px;
+ width: 180px;
+ }
+ }
+
+ .result.no-assign-to {
+ .list-row .level-right {
+ flex: 0 0 130px;
+ width: 130px;
+ }
}
}
.list-row {
- padding-right: 15px;
- height: var(--list-row-height);
border-radius: var(--border-radius);
cursor: pointer;
transition: color 0.2s;
@@ -90,6 +100,14 @@
&:hover:not(.list-row-head) {
background-color: var(--highlight-color);
+ border-radius: unset;
+ .level-right {
+ box-shadow: -5px 0px 5px var(--highlight-color);
+ }
+ }
+
+ &:hover .level-right {
+ background-color: var(--highlight-color);
}
&:last-child {
@@ -99,11 +117,14 @@
.level-left {
flex: 4;
min-width: 80%;
+ padding: var(--padding-xs) 0;
}
.level-right {
- flex: 1;
- overflow: visible;
- align-items: center;
+ position: sticky;
+ right: 0;
+ background-color: var(--bg-color);
+ box-shadow: -5px 0px 5px rgb(255, 255, 255);
+ padding: 6px 10px;
}
.tag-col {
@@ -180,6 +201,18 @@
.checkbox-actions {
display: none;
}
+ .level-right {
+ background-color: var(--subtle-fg);
+ border-radius: var(--border-radius);
+ height: var(--list-row-height);
+ box-shadow: none;
+ &:hover {
+ background-color: var(--subtle-fg);
+ }
+ }
+ &:hover .level-right {
+ background-color: var(--subtle-fg);
+ }
}
.list-row-col {
@@ -308,7 +341,6 @@ input.list-header-checkbox {
align-items: center;
cursor: pointer;
- height: var(--list-row-height);
padding-left: 15px;
@include get_textstyle("base", "regular");
@@ -499,3 +531,70 @@ input.list-header-checkbox {
height: calc(100vh - 284px);
z-index: 0;
}
+
+@media (max-width: map-get($grid-breakpoints, "lg")) {
+ .layout-main-section-wrapper {
+ width: 100%;
+ }
+ .frappe-list {
+ .list-row {
+ .level-right {
+ flex: 0 0 auto;
+ width: auto;
+ }
+ }
+ }
+}
+
+@media (max-width: map-get($grid-breakpoints, "sm")) {
+ .layout-main-section .frappe-list .result-container {
+ .result {
+ overflow: hidden;
+ input.list-row-checkbox,
+ input.list-header-checkbox {
+ width: 15px !important;
+ height: 15px;
+ }
+ }
+ .list-row-container:not(:has(.list-row-head)) {
+ .list-row {
+ &.level {
+ align-items: flex-start;
+ }
+ .level-left {
+ min-width: auto;
+ display: block;
+ .mobile-layout {
+ display: inline-block;
+ z-index: 1;
+ position: relative;
+ padding-left: 10px;
+ .list-row-col {
+ margin-right: 0px;
+ }
+ }
+ .mobile-layout:not(.mobile-layout ~ .mobile-layout) {
+ padding-left: 27px;
+ margin-right: 6px;
+
+ &::after {
+ content: "\2022";
+ position: absolute;
+ right: 0;
+ top: 50%;
+ transform: translate(50%, -50%);
+ padding-left: 15px;
+ }
+ }
+ }
+ .level-right {
+ flex: 0 0 auto;
+ width: auto;
+ .level-item.visible-xs {
+ margin-top: 5px;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/frappe/public/scss/desk/page.scss b/frappe/public/scss/desk/page.scss
index 044148534f..bd86a517e8 100644
--- a/frappe/public/scss/desk/page.scss
+++ b/frappe/public/scss/desk/page.scss
@@ -93,7 +93,8 @@
}
.layout-main-section-wrapper {
- width: 100%;
+ flex: 1 0 80%;
+ width: 80%;
}
.layout-main-section.frappe-card {
@@ -179,12 +180,39 @@
.layout-main-section {
scroll-margin-top: var(--navbar-height);
+ .frappe-list {
+ .result-container {
+ overflow-x: auto;
+ .result {
+ min-width: 100%;
+ width: auto;
+ .list-row-container {
+ width: fit-content;
+ min-width: 100%;
+ }
+ .list-row-container:first-child {
+ position: sticky;
+ top: 0;
+ z-index: 2;
+ }
+ .list-row-container {
+ .level-left {
+ .list-row-col {
+ min-width: 150px;
+ max-width: 400px;
+ }
+ }
+ }
+ }
+ }
+ }
+
.frappe-list,
.report-wrapper {
.result,
.no-result,
.freeze {
- min-height: "200px";
+ min-height: 200px;
}
.result {
@@ -221,3 +249,9 @@
margin-top: var(--margin-xs);
text-align: center;
}
+
+.frappe-control {
+ .form-control.fields_order {
+ padding-top: 1.5px;
+ }
+}