From 4f1d00442c88e487756cb5e3dc642312b177166c Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 17 Mar 2022 15:30:22 +0530 Subject: [PATCH 01/61] fix(as_json): Pop None key if exists JSON doesn't allow null key as per spec, it should be a string only: https://datatracker.ietf.org/doc/html/rfc7159#section-4 ref discussions: * https://github.com/frappe/frappe/issues/14292 * https://github.com/frappe/frappe/pull/14504/files#r821526085 --- frappe/__init__.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 86f8be35ea..60189a2565 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE """ Frappe - Low Code Open Source Framework in Python and JS @@ -20,10 +20,10 @@ if _dev_server: warnings.simplefilter('always', DeprecationWarning) warnings.simplefilter('always', PendingDeprecationWarning) -from werkzeug.local import Local, release_local import sys, importlib, inspect, json -import typing import click +from werkzeug.local import Local, release_local +from typing import TYPE_CHECKING, Dict, List, Union # Local application imports from .exceptions import * @@ -143,15 +143,14 @@ lang = local("lang") # This if block is never executed when running the code. It is only used for # telling static code analyzer where to find dynamically defined attributes. -if typing.TYPE_CHECKING: - from frappe.utils.redis_wrapper import RedisWrapper - +if TYPE_CHECKING: from frappe.database.mariadb.database import MariaDBDatabase from frappe.database.postgres.database import PostgresDatabase from frappe.query_builder.builder import MariaDB, Postgres + from frappe.utils.redis_wrapper import RedisWrapper - db: typing.Union[MariaDBDatabase, PostgresDatabase] - qb: typing.Union[MariaDB, Postgres] + db: Union[MariaDBDatabase, PostgresDatabase] + qb: Union[MariaDB, Postgres] # end: static analysis hack @@ -1522,12 +1521,14 @@ def get_value(*args, **kwargs): """ return db.get_value(*args, **kwargs) -def as_json(obj, indent=1): +def as_json(obj: Union[Dict, List], indent=1) -> str: from frappe.utils.response import json_handler - try: - return json.dumps(obj, indent=indent, sort_keys=True, default=json_handler, separators=(',', ': ')) - except TypeError: - return json.dumps(obj, indent=indent, default=json_handler, separators=(',', ': ')) + + if isinstance(obj, dict) and None in obj: + obj.pop(None) + + return json.dumps(obj, indent=indent, sort_keys=True, default=json_handler, separators=(',', ': ')) + def are_emails_muted(): from frappe.utils import cint From a6c9b23471feb5a6327ce3f8748c6a97e1e080db Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 02:05:02 +0100 Subject: [PATCH 02/61] refactor: use local method refresh_field --- frappe/public/js/frappe/form/form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 7ec6677c7f..2e33e5c8ac 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1707,7 +1707,7 @@ frappe.ui.form.Form = class FrappeForm { for(var i = 0; i < cl.length; i++){ if(!cl[i][fieldname]) cl[i][fieldname] = value; } - refresh_field("items"); + this.refresh_field("items"); } get_sum(table_fieldname, fieldname) { From 2718685368f89cbc62c0d56a53806e1f613fd53c Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 17:37:42 +0100 Subject: [PATCH 03/61] refactor: update_in_all_rows --- frappe/public/js/frappe/form/form.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 2e33e5c8ac..2c7a1e3543 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1701,13 +1701,17 @@ frappe.ui.form.Form = class FrappeForm { } update_in_all_rows(table_fieldname, fieldname, value) { - // update the child value in all tables where it is missing - if(!value) return; - var cl = this.doc[table_fieldname] || []; - for(var i = 0; i < cl.length; i++){ - if(!cl[i][fieldname]) cl[i][fieldname] = value; - } - this.refresh_field("items"); + // Update the `value` of the field named `fieldname` in all rows of the + // child table named `table_fieldname`. + // Do not overwrite existing values. + if (!value) return; + + frappe.model + .get_children(this.doc, table_fieldname) + .filter(child => !child[fieldname]) + .forEach(child => + frappe.model.set_value(child.doctype, child.name, fieldname, value) + ); } get_sum(table_fieldname, fieldname) { From 38c6db06ea1d25d9a13775efc3b2145823ce1bdb Mon Sep 17 00:00:00 2001 From: Komal-Saraf0609 Date: Mon, 21 Mar 2022 13:13:19 +0530 Subject: [PATCH 04/61] test: Added test script for control type "Dynamic Link" --- cypress/integration/control_dynamiclink.js | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 cypress/integration/control_dynamiclink.js diff --git a/cypress/integration/control_dynamiclink.js b/cypress/integration/control_dynamiclink.js new file mode 100644 index 0000000000..590ab37c3b --- /dev/null +++ b/cypress/integration/control_dynamiclink.js @@ -0,0 +1,34 @@ +context('Dynamic Link', () => { + before(() => { + cy.login(); + cy.visit('/app/doctype'); + return cy.window().its('frappe').then(frappe => { + return frappe.xcall('frappe.tests.ui_test_helpers.create_doctype', { + name: 'Test Dynamic Link', + fields: [ + { + "label": "Document Type", + "fieldname": "doc_type", + "fieldtype": "Link", + "options": "DocType", + "in_list_view": 1, + }, + { + "label": "Document ID", + "fieldname": "doc_id", + "fieldtype": "Dynamic Link", + "options": "doc_type", + "in_list_view": 1, + }, + ] + }); + }); + }); + it('Creating a dynamic link and verifying it', () => { + cy.new_form('Test Dynamic Link'); + cy.get('form > [data-fieldname="doc_type"]').type('User'); + cy.get('form > [data-fieldname="doc_id"]').click(); + cy.get('[id="awesomplete_list_4"]').its('length').should('be.gte', 0); + + }); +}); From 9b69f4e08c1811a1b3e9a87b08335ad9c5193fc0 Mon Sep 17 00:00:00 2001 From: Komal-Saraf0609 Date: Mon, 21 Mar 2022 13:32:16 +0530 Subject: [PATCH 05/61] test: fixing sider issues --- cypress/integration/control_dynamiclink.js | 56 +++++++++++----------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/cypress/integration/control_dynamiclink.js b/cypress/integration/control_dynamiclink.js index 590ab37c3b..206d04e5f2 100644 --- a/cypress/integration/control_dynamiclink.js +++ b/cypress/integration/control_dynamiclink.js @@ -1,34 +1,34 @@ context('Dynamic Link', () => { - before(() => { - cy.login(); - cy.visit('/app/doctype'); - return cy.window().its('frappe').then(frappe => { - return frappe.xcall('frappe.tests.ui_test_helpers.create_doctype', { - name: 'Test Dynamic Link', - fields: [ - { - "label": "Document Type", - "fieldname": "doc_type", - "fieldtype": "Link", - "options": "DocType", - "in_list_view": 1, - }, - { - "label": "Document ID", - "fieldname": "doc_id", - "fieldtype": "Dynamic Link", - "options": "doc_type", - "in_list_view": 1, - }, - ] - }); - }); - }); - it('Creating a dynamic link and verifying it', () => { - cy.new_form('Test Dynamic Link'); + before(() => { + cy.login(); + cy.visit('/app/doctype'); + return cy.window().its('frappe').then(frappe => { + return frappe.xcall('frappe.tests.ui_test_helpers.create_doctype', { + name: 'Test Dynamic Link', + fields: [ + { + "label": "Document Type", + "fieldname": "doc_type", + "fieldtype": "Link", + "options": "DocType", + "in_list_view": 1, + }, + { + "label": "Document ID", + "fieldname": "doc_id", + "fieldtype": "Dynamic Link", + "options": "doc_type", + "in_list_view": 1, + }, + ] + }); + }); + }); + it('Creating a dynamic link and verifying it', () => { + cy.new_form('Test Dynamic Link'); cy.get('form > [data-fieldname="doc_type"]').type('User'); cy.get('form > [data-fieldname="doc_id"]').click(); cy.get('[id="awesomplete_list_4"]').its('length').should('be.gte', 0); - }); + }); }); From a139d1d369b5a24e8c4c0e2a7cedcfed7dd9fa90 Mon Sep 17 00:00:00 2001 From: Komal-Saraf0609 Date: Mon, 21 Mar 2022 13:39:22 +0530 Subject: [PATCH 06/61] test: fixing sider issues --- cypress/integration/control_dynamiclink.js | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/cypress/integration/control_dynamiclink.js b/cypress/integration/control_dynamiclink.js index 206d04e5f2..c989889ca2 100644 --- a/cypress/integration/control_dynamiclink.js +++ b/cypress/integration/control_dynamiclink.js @@ -2,27 +2,27 @@ context('Dynamic Link', () => { before(() => { cy.login(); cy.visit('/app/doctype'); - return cy.window().its('frappe').then(frappe => { - return frappe.xcall('frappe.tests.ui_test_helpers.create_doctype', { - name: 'Test Dynamic Link', - fields: [ - { - "label": "Document Type", - "fieldname": "doc_type", - "fieldtype": "Link", - "options": "DocType", - "in_list_view": 1, - }, - { - "label": "Document ID", - "fieldname": "doc_id", - "fieldtype": "Dynamic Link", - "options": "doc_type", - "in_list_view": 1, - }, - ] - }); + return cy.window().its('frappe').then(frappe => { + return frappe.xcall('frappe.tests.ui_test_helpers.create_doctype', { + name: 'Test Dynamic Link', + fields: [ + { + "label": "Document Type", + "fieldname": "doc_type", + "fieldtype": "Link", + "options": "DocType", + "in_list_view": 1, + }, + { + "label": "Document ID", + "fieldname": "doc_id", + "fieldtype": "Dynamic Link", + "options": "doc_type", + "in_list_view": 1, + }, + ] }); + }); }); it('Creating a dynamic link and verifying it', () => { cy.new_form('Test Dynamic Link'); From 7fbbf577c90cbb877dc34c42b5e925373b2d34a4 Mon Sep 17 00:00:00 2001 From: Komal-Saraf0609 Date: Mon, 21 Mar 2022 13:44:33 +0530 Subject: [PATCH 07/61] test: fixing sider issues --- cypress/integration/control_dynamiclink.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cypress/integration/control_dynamiclink.js b/cypress/integration/control_dynamiclink.js index c989889ca2..bef4034120 100644 --- a/cypress/integration/control_dynamiclink.js +++ b/cypress/integration/control_dynamiclink.js @@ -4,21 +4,21 @@ context('Dynamic Link', () => { cy.visit('/app/doctype'); return cy.window().its('frappe').then(frappe => { return frappe.xcall('frappe.tests.ui_test_helpers.create_doctype', { - name: 'Test Dynamic Link', + name: 'Test Dynamic Link', fields: [ { - "label": "Document Type", - "fieldname": "doc_type", - "fieldtype": "Link", - "options": "DocType", - "in_list_view": 1, + "label": "Document Type", + "fieldname": "doc_type", + "fieldtype": "Link", + "options": "DocType", + "in_list_view": 1, }, { - "label": "Document ID", - "fieldname": "doc_id", - "fieldtype": "Dynamic Link", - "options": "doc_type", - "in_list_view": 1, + "label": "Document ID", + "fieldname": "doc_id", + "fieldtype": "Dynamic Link", + "options": "doc_type", + "in_list_view": 1, }, ] }); From df62607c4324df555ad6c3c0c4e0c961a08ee6ae Mon Sep 17 00:00:00 2001 From: Komal-Saraf0609 Date: Mon, 21 Mar 2022 17:02:59 +0530 Subject: [PATCH 08/61] test: Corrected the selector --- cypress/integration/control_dynamiclink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/integration/control_dynamiclink.js b/cypress/integration/control_dynamiclink.js index bef4034120..3df33acc3f 100644 --- a/cypress/integration/control_dynamiclink.js +++ b/cypress/integration/control_dynamiclink.js @@ -28,7 +28,7 @@ context('Dynamic Link', () => { cy.new_form('Test Dynamic Link'); cy.get('form > [data-fieldname="doc_type"]').type('User'); cy.get('form > [data-fieldname="doc_id"]').click(); - cy.get('[id="awesomplete_list_4"]').its('length').should('be.gte', 0); + cy.get_field("doc_id").its('length').should('be.gte', 0); }); }); From 12f69fb39996e10a3c8c264ba3ec3c4f0cfa386d Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Mon, 21 Mar 2022 13:15:37 +0100 Subject: [PATCH 09/61] fix: allow falsy values Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/public/js/frappe/form/form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 2c7a1e3543..46054dd91b 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1704,7 +1704,7 @@ frappe.ui.form.Form = class FrappeForm { // Update the `value` of the field named `fieldname` in all rows of the // child table named `table_fieldname`. // Do not overwrite existing values. - if (!value) return; + if (value === undefined) return; frappe.model .get_children(this.doc, table_fieldname) From 1c8d2fd5369f76700130fd4c33d31bcaed0f779c Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 21 Mar 2022 17:49:26 +0530 Subject: [PATCH 10/61] fix: Sort keys for illegal JSON --- frappe/__init__.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 60189a2565..df8e1fbfb1 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -1524,11 +1524,13 @@ def get_value(*args, **kwargs): def as_json(obj: Union[Dict, List], indent=1) -> str: from frappe.utils.response import json_handler - if isinstance(obj, dict) and None in obj: - obj.pop(None) - - return json.dumps(obj, indent=indent, sort_keys=True, default=json_handler, separators=(',', ': ')) - + try: + return json.dumps(obj, indent=indent, sort_keys=True, default=json_handler, separators=(',', ': ')) + except TypeError: + # this would break in case the keys are not all os "str" type - as defined in the JSON + # adding this to ensure keys are sorted (expected behaviour) + sorted_obj = dict(sorted(obj.items(), key=lambda kv: str(kv[0]))) + return json.dumps(sorted_obj, indent=indent, default=json_handler, separators=(',', ': ')) def are_emails_muted(): from frappe.utils import cint From 118d9286289f51447e2c812b8382bd3c201a8e26 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 22 Mar 2022 16:26:46 +0100 Subject: [PATCH 11/61] refactor: use frappe.model.has_value to determine if field is empty --- frappe/public/js/frappe/form/form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 46054dd91b..6191e35073 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1708,7 +1708,7 @@ frappe.ui.form.Form = class FrappeForm { frappe.model .get_children(this.doc, table_fieldname) - .filter(child => !child[fieldname]) + .filter(child => !frappe.model.has_value(child.doctype, child.name, fieldname)) .forEach(child => frappe.model.set_value(child.doctype, child.name, fieldname, value) ); From a9b8fe8197e3b3f2d4cd0b91bbc6d271f83380a5 Mon Sep 17 00:00:00 2001 From: leoajr <99390381+leoajr@users.noreply.github.com> Date: Wed, 23 Mar 2022 13:59:39 +0100 Subject: [PATCH 12/61] docs: incorrect argname in docs for get_list #16384 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index ac0d1a3b8f..0abaf932a7 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -1465,7 +1465,7 @@ def get_list(doctype, *args, **kwargs): :param fields: List of fields or `*`. :param filters: List of filters (see example). :param order_by: Order By e.g. `modified desc`. - :param limit_page_start: Start results at record #. Default 0. + :param limit_start: Start results at record #. Default 0. :param limit_page_length: No of records in the page. Default 20. Example usage: From 4bb5ea609cd83c92e8d7b170cb8f899440a1f4f8 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 23 Mar 2022 19:28:01 +0530 Subject: [PATCH 13/61] fix: get currency name from DB only if `options` are set and value is truthy (#16382) * fix: call `frappe.db.exists` only if `options` are set and value is truthy * fix: sider issue Co-authored-by: Ankush Menat * fix: use `get_value` instead of `exists` Co-authored-by: Ankush Menat * test: ensure currency formatting works without currency set in df options or param Co-authored-by: Ankush Menat --- frappe/model/base_document.py | 11 +++++++---- frappe/tests/test_document.py | 6 +++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 57b4777355..8fd64689fc 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -963,10 +963,13 @@ class BaseDocument(object): from frappe.model.meta import get_default_df df = get_default_df(fieldname) - if df.fieldtype == "Currency" and not currency: - currency = self.get(df.get("options")) - if not frappe.db.exists('Currency', currency, cache=True): - currency = None + if ( + df.fieldtype == "Currency" + and not currency + and (currency_field := df.get("options")) + and (currency_value := self.get(currency_field)) + ): + currency = frappe.db.get_value('Currency', currency_value, cache=True) val = self.get(fieldname) diff --git a/frappe/tests/test_document.py b/frappe/tests/test_document.py index 169d1ebb2c..5caccb167e 100644 --- a/frappe/tests/test_document.py +++ b/frappe/tests/test_document.py @@ -246,7 +246,7 @@ class TestDocument(unittest.TestCase): 'fields': [ {'label': 'Currency', 'fieldname': 'currency', 'reqd': 1, 'fieldtype': 'Currency'}, ] - }).insert() + }).insert(ignore_if_duplicate=True) frappe.delete_doc_if_exists("Currency", "INR", 1) @@ -262,6 +262,10 @@ class TestDocument(unittest.TestCase): }) self.assertEqual(d.get_formatted('currency', currency='INR', format="#,###.##"), '₹ 100,000.00') + # should work even if options aren't set in df + # and currency param is not passed + self.assertIn("0", d.get_formatted("currency")) + def test_limit_for_get(self): doc = frappe.get_doc("DocType", "DocType") # assuming DocType has more than 3 Data fields From d253b5e5e4351ecd1fc0980ed3dd3ac41a97c720 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 24 Mar 2022 08:32:50 +0530 Subject: [PATCH 14/61] fix: Global filter check --- frappe/public/scss/desk/sidebar.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/scss/desk/sidebar.scss b/frappe/public/scss/desk/sidebar.scss index 0bb6ba5f40..e30e0c3b94 100644 --- a/frappe/public/scss/desk/sidebar.scss +++ b/frappe/public/scss/desk/sidebar.scss @@ -355,7 +355,7 @@ body[data-route^="Module"] .main-menu { display: none; } - input { + input:not([data-fieldtype='Check']) { background: var(--control-bg-on-gray); } From b66011de5ad79d7264a58a5bcb210a54231e583b Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 21 Mar 2022 16:38:41 +0530 Subject: [PATCH 15/61] feat(website): added new templates to page builder and refactored typography to be more consistent --- frappe/public/scss/desk/avatar.scss | 4 +- frappe/public/scss/website/base.scss | 67 +++++++++-- frappe/public/scss/website/blog.scss | 4 +- frappe/public/scss/website/index.scss | 2 +- frappe/public/scss/website/markdown.scss | 112 ++---------------- frappe/public/scss/website/page_builder.scss | 102 +++++++++++----- frappe/public/scss/website/variables.scss | 2 +- frappe/templates/includes/avatar_macro.html | 16 +-- frappe/templates/includes/blog/blogger.html | 7 +- frappe/templates/includes/web_block.html | 7 +- .../website/doctype/blog_post/blog_post.json | 6 +- .../blog_post/templates/blog_post_row.html | 4 +- frappe/website/doctype/web_page/web_page.js | 2 +- .../web_page_block/web_page_block.json | 37 +++++- frappe/website/js/website.js | 13 ++ .../web_template/cover_image/__init__.py | 0 .../web_template/cover_image/cover_image.html | 5 + .../web_template/cover_image/cover_image.json | 34 ++++++ .../full_width_image/full_width_image.json | 4 +- frappe/website/web_template/hero/hero.html | 4 +- frappe/website/web_template/hero/hero.json | 3 +- .../section_with_cta/section_with_cta.html | 8 +- .../section_with_small_cta.html | 8 +- .../section_with_testimonials/__init__.py | 0 .../section_with_testimonials.html | 31 +++++ .../section_with_testimonials.json | 73 ++++++++++++ .../section_with_videos/__init__.py | 0 .../section_with_videos.html | 24 ++++ .../section_with_videos.json | 61 ++++++++++ 29 files changed, 460 insertions(+), 180 deletions(-) create mode 100644 frappe/website/web_template/cover_image/__init__.py create mode 100644 frappe/website/web_template/cover_image/cover_image.html create mode 100644 frappe/website/web_template/cover_image/cover_image.json create mode 100644 frappe/website/web_template/section_with_testimonials/__init__.py create mode 100644 frappe/website/web_template/section_with_testimonials/section_with_testimonials.html create mode 100644 frappe/website/web_template/section_with_testimonials/section_with_testimonials.json create mode 100644 frappe/website/web_template/section_with_videos/__init__.py create mode 100644 frappe/website/web_template/section_with_videos/section_with_videos.html create mode 100644 frappe/website/web_template/section_with_videos/section_with_videos.json diff --git a/frappe/public/scss/desk/avatar.scss b/frappe/public/scss/desk/avatar.scss index cc8c16ce44..638256c21d 100644 --- a/frappe/public/scss/desk/avatar.scss +++ b/frappe/public/scss/desk/avatar.scss @@ -111,8 +111,8 @@ } .avatar-large { - width: 72px; - height: 72px; + width: 64px; + height: 64px; .standard-image { font-size: var(--text-2xl); diff --git a/frappe/public/scss/website/base.scss b/frappe/public/scss/website/base.scss index 4190780ece..324397552d 100644 --- a/frappe/public/scss/website/base.scss +++ b/frappe/public/scss/website/base.scss @@ -1,3 +1,13 @@ +$font-size-xs: 0.7rem; +$font-size-sm: 0.85rem; +$font-size-lg: 1.12rem; +$font-size-xl: 1.25rem; +$font-size-2xl: 1.5rem; +$font-size-3xl: 2rem; +$font-size-4xl: 2.5rem; +$font-size-5xl: 3rem; +$font-size-6xl: 4rem; + html { height: 100%; } @@ -16,43 +26,74 @@ img { h1 { font-size: $font-size-3xl; - font-weight: 800; line-height: 1.25; letter-spacing: -0.025em; - margin-bottom: 1rem; + margin-top: 3rem; + margin-bottom: 0.75rem; @include media-breakpoint-up(sm) { + font-size: $font-size-5xl; line-height: 2.5rem; - font-size: $font-size-4xl; + margin-top: 3.5rem; + margin-bottom: 1.25rem; } @include media-breakpoint-up(xl) { + font-size: $font-size-6xl; line-height: 1; - font-size: $font-size-5xl; + margin-top: 4rem; } } h2 { - font-size: $font-size-xl; - font-weight: 700; + font-size: $font-size-2xl; + margin-top: 2rem; margin-bottom: 0.75rem; @include media-breakpoint-up(sm) { - font-size: $font-size-2xl; - } - @include media-breakpoint-up(md) { font-size: $font-size-3xl; + margin-top: 4rem; + margin-bottom: 1rem; + } + @include media-breakpoint-up(xl) { + font-size: $font-size-4xl; + margin-top: 4rem; } } h3 { - font-size: $font-size-base; - font-weight: 600; + font-size: $font-size-xl; + margin-top: 1.5rem; margin-bottom: 0.5rem; @include media-breakpoint-up(sm) { - font-size: $font-size-lg; + font-size: $font-size-2xl; + margin-top: 2.5rem; + } + @include media-breakpoint-up(xl) { + font-size: $font-size-3xl; + margin-top: 3.5rem; } - @include media-breakpoint-up(md) { +} + +h4 { + font-size: $font-size-lg; + margin-top: 1rem; + margin-bottom: 0.5rem; + + @include media-breakpoint-up(sm) { font-size: $font-size-xl; + margin-top: 1.25rem; } + @include media-breakpoint-up(xl) { + font-size: $font-size-2xl; + margin-top: 1.75rem; + } + + a { + color: $body-color; + } +} + +.btn.btn-lg { + font-size: $font-size-lg; } diff --git a/frappe/public/scss/website/blog.scss b/frappe/public/scss/website/blog.scss index 6b0acb9d83..99255df764 100644 --- a/frappe/public/scss/website/blog.scss +++ b/frappe/public/scss/website/blog.scss @@ -57,12 +57,12 @@ .blog-card-footer { display: flex; - align-items: center; + align-items: top; margin-top: 0.5rem; .avatar { + margin-top: 0.4rem; margin-right: 0.5rem; - border-radius: 50%; } } } diff --git a/frappe/public/scss/website/index.scss b/frappe/public/scss/website/index.scss index e36e649eb7..4352301b4c 100644 --- a/frappe/public/scss/website/index.scss +++ b/frappe/public/scss/website/index.scss @@ -5,7 +5,6 @@ @import "../common/global"; @import "../common/icons"; @import "../common/alert"; -@import 'base'; @import "../common/flex"; @import "../common/buttons"; @import "../common/modal"; @@ -14,6 +13,7 @@ @import "../common/indicator"; @import "../common/controls"; @import "../common/awesomeplete"; +@import 'base'; @import 'multilevel_dropdown'; @import 'website_image'; @import 'website_avatar'; diff --git a/frappe/public/scss/website/markdown.scss b/frappe/public/scss/website/markdown.scss index 6f009df393..c2592b61e9 100644 --- a/frappe/public/scss/website/markdown.scss +++ b/frappe/public/scss/website/markdown.scss @@ -1,30 +1,12 @@ -$font-sizes-desktop: ( - "sm": 0.75rem, - "base": 1rem, - "lg": 1.125rem, - "xl": 1.41rem, - "2xl": 1.6rem, - "3xl": 2rem -); - -$font-sizes-mobile: ( - "sm": 0.75rem, - "base": 1rem, - "lg": 1.125rem, - "xl": 1.25rem, - "2xl": 1.5rem, - "3xl": 1.75rem -); + +.section-markdown > .from-markdown { + max-width: 50rem; + margin: auto; +} .from-markdown { color: $gray-700; line-height: 1.7; - letter-spacing: -0.011em; - - > * + * { - margin-top: 0.75rem; - margin-bottom: 0; - } > :first-child { margin-top: 0; @@ -47,6 +29,10 @@ $font-sizes-mobile: ( list-style: decimal; } + p, li { + font-size: $font-size-lg; + } + li { padding-top: 1px; padding-bottom: 1px; @@ -87,86 +73,6 @@ $font-sizes-mobile: ( font-weight: 600; } - h1, h2, h3, h4, h5, h6 { - color: $gray-900; - } - - h2, h3, h4, h5, h6 { - font-weight: 600; - } - - h1 { - font-size: map-get($font-sizes-mobile, '3xl'); - line-height: 1.5; - letter-spacing: -0.021em; - font-weight: 700; - - @include media-breakpoint-up(md) { - font-size: map-get($font-sizes-desktop, '3xl'); - letter-spacing: -0.024em; - } - - // for byline - & + p { - margin-top: 1.5rem; - font-size: map-get($font-sizes-mobile, 'xl'); - letter-spacing: -0.014em; - line-height: 1.4; - - @include media-breakpoint-up(md) { - font-size: map-get($font-sizes-desktop, 'xl'); - letter-spacing: -0.0175em; - } - } - } - - h2 { - font-size: map-get($font-sizes-mobile, '2xl'); - line-height: 1.56; - letter-spacing: -0.015em; - margin-top: 4rem; - - @include media-breakpoint-up(md) { - font-size: map-get($font-sizes-desktop, '2xl'); - letter-spacing: -0.0195em; - } - } - - h3 { - font-size: map-get($font-sizes-mobile, 'xl'); - line-height: 1.56; - letter-spacing: -0.014em; - margin-top: 2.25rem; - - @include media-breakpoint-up(md) { - font-size: map-get($font-sizes-desktop, 'xl'); - letter-spacing: -0.0175em; - } - } - - h4 { - font-size: map-get($font-sizes-mobile, 'lg'); - line-height: 1.56; - letter-spacing: -0.014em; - margin-top: 2.5rem; - } - - h5 { - font-size: map-get($font-sizes-mobile, 'base'); - line-height: 1.5; - letter-spacing: -0.011em; - font-weight: 600; - margin-top: 2rem; - } - - h6 { - font-size: map-get($font-sizes-mobile, 'sm'); - line-height: 1.35; - font-weight: 600; - text-transform: uppercase; - margin-top: 1.5rem; - } - tr > td, tr > th { font-size: $font-size-sm; diff --git a/frappe/public/scss/website/page_builder.scss b/frappe/public/scss/website/page_builder.scss index e7e2f8b242..f94f79df21 100644 --- a/frappe/public/scss/website/page_builder.scss +++ b/frappe/public/scss/website/page_builder.scss @@ -1,4 +1,7 @@ .hero-content { + margin-top: 3rem; + margin-bottom: 3rem; + .btn-primary { margin-top: 1rem; margin-right: 0.5rem; @@ -15,16 +18,23 @@ .hero-title, .hero-subtitle { max-width: 42rem; + margin-top: 0rem; + margin-bottom: 0.5rem; +} + +.lead { + font-weight: normal; + font-size: 1.25rem; + margin-bottom: 1.5rem; } .hero-subtitle { @extend .lead; - font-weight: 400; color: $gray-600; - font-size: 1rem; + font-size: $font-size-lg; @include media-breakpoint-up(sm) { - font-size: 1.25rem; + font-size: $font-size-xl; } } @@ -42,10 +52,10 @@ .section-description { max-width: 56rem; margin-top: 0.5rem; - font-size: $font-size-base; + font-size: $font-size-lg; - @include media-breakpoint-up(lg) { - font-size: $font-size-lg; + @include media-breakpoint-up(media-breakpoint-up) { + font-size: $font-size-xl; } } @@ -226,14 +236,10 @@ } } -.section-markdown > .from-markdown { - max-width: 42rem; -} - .section-cta { padding: 3rem 2rem; text-align: center; - background-color: $primary-light; + background-color: $gray-200; border-radius: 0.75rem; @include media-breakpoint-up(sm) { @@ -248,12 +254,7 @@ .title { margin: 0 auto; max-width: 36rem; - font-size: $font-size-2xl; - font-weight: 800; line-height: 1.25; - @include media-breakpoint-up(md) { - font-size: $font-size-4xl; - } } .subtitle { max-width: 36rem; @@ -270,11 +271,15 @@ margin-top: 0.5rem; font-size: $font-size-xs; } + .action { + margin-top: 0; + margin-bottom: 0; + } } .section-small-cta { padding: 1.8rem; - background-color: lighten($primary, 42%); + background-color: var(--gray-200); border-radius: 0.75rem; display: flex; flex-direction: column; @@ -294,26 +299,27 @@ } } - .title { - max-width: 36rem; - font-size: $font-size-xl; - font-weight: 800; - line-height: 1.25; - @include media-breakpoint-up(md) { - font-size: $font-size-2xl; - } + .section-title { + line-height: 1; + margin-bottom: 0.25rem; } + .subtitle { max-width: 36rem; font-size: $font-size-base; color: $gray-900; - margin-bottom: 1.2rem; + margin-bottom: 0.5rem; @include media-breakpoint-up(md) { font-size: $font-size-lg; margin-bottom: 0px; } } + + .action { + margin-top: 0; + margin-bottom: 0; + } } .section-cta-container { @@ -379,6 +385,20 @@ } } +.testimonial-author { + margin-top: 1rem; + display: flex; + align-items: center; + + .avatar { + margin-right: 0.5rem; + } + + p { + margin-bottom: 0; + } +} + .split-section-content.align-top { margin-top: 2rem; } @@ -514,12 +534,12 @@ @include media-breakpoint-up(md) { grid-template-columns: repeat(2, 1fr); - gap: 6rem; + gap: 3rem 5rem; } .feature-title { font-size: $font-size-xl; - font-weight: bold; + font-weight: 600; @include media-breakpoint-up(md) { font-size: $font-size-2xl; @@ -528,7 +548,7 @@ .feature-content { font-size: $font-size-base; - margin-top: 1.75rem; + margin-top: 1.25rem; @include media-breakpoint-up(xl) { font-size: $font-size-lg; @@ -630,9 +650,14 @@ } } +.section-title { + margin-top: 0; + margin-bottom: 0.5rem; +} + .section-title + .section-features, .section-description + .section-features { &[data-columns="2"] { - margin-top: 3.75rem; + margin-top: 3rem; } &[data-columns="3"] { @@ -651,6 +676,10 @@ position: relative; } +.feature-title { + margin-top: 0; +} + .feature-title, .feature-content { margin-bottom: 0; } @@ -666,3 +695,16 @@ .section-with-embed .embed-container { margin-top: 2rem; } + +.section-video { + aspect-ratio: 16 / 9; + width: 100%; + cursor: pointer; + margin-bottom: 1rem; +} + +.video-thumbnail { + aspect-ratio: 16 / 9; + width: 100%; + object-fit: cover; +} diff --git a/frappe/public/scss/website/variables.scss b/frappe/public/scss/website/variables.scss index 293d02b06d..ad3dbd2f8b 100644 --- a/frappe/public/scss/website/variables.scss +++ b/frappe/public/scss/website/variables.scss @@ -58,7 +58,7 @@ $font-size-lg: 1.125rem !default; $font-size-xl: 1.25rem !default; $font-size-2xl: 1.5rem !default; $font-size-3xl: 1.875rem !default; -$font-size-4xl: 2.25rem !default; +$font-size-4xl: 2.5rem !default; $font-size-5xl: 3rem !default; $font-size-6xl: 4rem !default; diff --git a/frappe/templates/includes/avatar_macro.html b/frappe/templates/includes/avatar_macro.html index b652b573b3..49c2dfc1bc 100644 --- a/frappe/templates/includes/avatar_macro.html +++ b/frappe/templates/includes/avatar_macro.html @@ -1,18 +1,18 @@ -{% macro avatar(user_id=None, css_style=None, size="avatar-small") %} +{% macro avatar(user_id=None, css_style=None, size="avatar-small", full_name=None, image=None) %} {% set user_info = frappe.utils.get_user_info_for_avatar(user_id) %} - - {% if user_info.image %} + + {% if image or user_info.image %} + src="{{ image or user_info.image }}" + title="{{ full_name or user_info.name }}"> {% else %} - {{ frappe.utils.get_abbr(user_info.name).upper() }} + title="{{ full_name or user_info.name }}"> + {{ frappe.utils.get_abbr(full_name or user_info.name).upper() }} {% endif %} -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/frappe/templates/includes/blog/blogger.html b/frappe/templates/includes/blog/blogger.html index 6963cc7361..bc36501ddd 100644 --- a/frappe/templates/includes/blog/blogger.html +++ b/frappe/templates/includes/blog/blogger.html @@ -1,8 +1,9 @@ -{% from "frappe/templates/includes/macros.html" import square_image_with_fallback %} +{% from "frappe/templates/includes/avatar_macro.html" import avatar %}
- {{ square_image_with_fallback(src=blogger_info.avatar, size='small', alt=blogger_info.full_name, class='align-self-start mr-4 rounded') }} -
+ {{ avatar(full_name=blogger_info.full_name, image=blogger_info.avatar, size='avatar-large') }} + +
{{ blogger_info.full_name }}
diff --git a/frappe/templates/includes/web_block.html b/frappe/templates/includes/web_block.html index 0805e743c0..c8b22b3551 100644 --- a/frappe/templates/includes/web_block.html +++ b/frappe/templates/includes/web_block.html @@ -3,6 +3,8 @@ 'section-padding-top': web_block.add_top_padding, 'section-padding-bottom': web_block.add_bottom_padding, 'bg-light': web_block.add_shade, + 'border-top': web_block.add_border_at_top, + 'border-bottom': web_block.add_border_at_bottom, }, web_block.css_class ]) -%} @@ -10,7 +12,10 @@ {%- if web_template_type == 'Section' -%} {%- if not web_block.hide_block -%}
+ data-section-template="{{ web_block.web_template | e }}" + {% if web_block.add_background_image -%} + style="background: url({{ web_block.background_image}}) no-repeat center center; background-size: cover;" + {%- endif %}> {%- if web_block.add_container -%}
{%- endif -%} diff --git a/frappe/website/doctype/blog_post/blog_post.json b/frappe/website/doctype/blog_post/blog_post.json index 5e3cc78d70..3f8407e8e2 100644 --- a/frappe/website/doctype/blog_post/blog_post.json +++ b/frappe/website/doctype/blog_post/blog_post.json @@ -113,6 +113,7 @@ "depends_on": "eval:doc.content_type === 'Markdown'", "fieldname": "content_md", "fieldtype": "Markdown Editor", + "ignore_xss_filter": 1, "label": "Content (Markdown)" }, { @@ -213,7 +214,7 @@ "index_web_pages_for_search": 1, "is_published_field": "published", "links": [], - "modified": "2022-03-09 01:48:25.227295", + "modified": "2022-03-21 14:42:19.282612", "modified_by": "Administrator", "module": "Website", "name": "Blog Post", @@ -245,6 +246,7 @@ "route": "blog", "sort_field": "modified", "sort_order": "ASC", + "states": [], "title_field": "title", "track_changes": 1 -} +} \ No newline at end of file diff --git a/frappe/website/doctype/blog_post/templates/blog_post_row.html b/frappe/website/doctype/blog_post/templates/blog_post_row.html index 53539c33e0..f8494d12b0 100644 --- a/frappe/website/doctype/blog_post/templates/blog_post_row.html +++ b/frappe/website/doctype/blog_post/templates/blog_post_row.html @@ -1,3 +1,5 @@ +{% from "frappe/templates/includes/avatar_macro.html" import avatar %} + {%- set post = doc -%}
@@ -26,7 +28,7 @@

{{ post.intro }}