Merge branch 'develop' of github.com:frappe/frappe into onboarding-enhancements
This commit is contained in:
commit
26ef8fc034
69 changed files with 1519 additions and 1896 deletions
43
.snyk
43
.snyk
|
|
@ -1,5 +1,5 @@
|
|||
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
||||
version: v1.13.5
|
||||
version: v1.14.1
|
||||
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
|
||||
ignore:
|
||||
SNYK-JS-AWESOMPLETE-174474:
|
||||
|
|
@ -22,3 +22,44 @@ patch:
|
|||
SNYK-JS-LODASH-450202:
|
||||
- frappe-datatable > lodash:
|
||||
patched: '2020-01-31T01:33:09.889Z'
|
||||
SNYK-JS-LODASH-567746:
|
||||
- frappe-datatable > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- quagga > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- tailwindcss > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- '@tailwindcss/ui > @tailwindcss/custom-forms > lodash':
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > @snyk/dep-graph > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > inquirer > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > snyk-config > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > snyk-mvn-plugin > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > snyk-nodejs-lockfile-parser > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > snyk-nuget-plugin > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > @snyk/dep-graph > graphlib > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > snyk-go-plugin > graphlib > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > snyk-nodejs-lockfile-parser > graphlib > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > @snyk/snyk-cocoapods-plugin > @snyk/dep-graph > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > snyk-nuget-plugin > dotnet-deps-parser > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > snyk-php-plugin > @snyk/composer-lockfile-parser > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > @snyk/snyk-cocoapods-plugin > @snyk/dep-graph > graphlib > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > @snyk/snyk-cocoapods-plugin > @snyk/cocoapods-lockfile-parser > @snyk/ruby-semver > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
- snyk > @snyk/snyk-cocoapods-plugin > @snyk/cocoapods-lockfile-parser > @snyk/dep-graph > graphlib > lodash:
|
||||
patched: '2020-04-30T23:02:32.330Z'
|
||||
|
|
|
|||
|
|
@ -102,7 +102,13 @@ install:
|
|||
- if [ $TYPE == "server" ]; then sed -i 's/socketio:/# socketio:/g' Procfile; fi
|
||||
- if [ $TYPE == "server" ]; then sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile; fi
|
||||
|
||||
- bench setup requirements --node
|
||||
- if [ $TYPE == "ui" ]; then bench setup requirements --node; fi
|
||||
|
||||
# install node-sass which is required for website theme test
|
||||
- cd ./apps/frappe
|
||||
- yarn add node-sass@4.13.1
|
||||
- cd ../..
|
||||
|
||||
- bench start &
|
||||
- bench --site test_site reinstall --yes
|
||||
- bench --site test_site_producer reinstall --yes
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ def console(context):
|
|||
for app in all_apps:
|
||||
locals()[app] = __import__(app)
|
||||
print("Apps in this namespace:\n{}".format(", ".join(all_apps)))
|
||||
IPython.embed(display_banner="", header="")
|
||||
IPython.embed(display_banner="", header="", colors="neutral")
|
||||
|
||||
|
||||
@click.command('run-tests')
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class TestExporter(unittest.TestCase):
|
|||
e = Exporter('Web Page', export_fields='All')
|
||||
csv_array = e.get_csv_array()
|
||||
header = csv_array[0]
|
||||
self.assertEqual(len(header), 36)
|
||||
self.assertEqual(len(header), 37)
|
||||
|
||||
|
||||
def test_exports_selected_fields(self):
|
||||
|
|
|
|||
|
|
@ -299,7 +299,6 @@ def export_query():
|
|||
_("You can try changing the filters of your report."))
|
||||
return
|
||||
|
||||
data.columns = [col for col in data.columns if isinstance(col, dict) and not col.get('hidden')]
|
||||
columns = get_columns_dict(data.columns)
|
||||
|
||||
from frappe.utils.xlsxutils import make_xlsx
|
||||
|
|
@ -316,7 +315,8 @@ def build_xlsx_data(columns, data, visible_idx, include_indentation):
|
|||
|
||||
# add column headings
|
||||
for idx in range(len(data.columns)):
|
||||
result[0].append(columns[idx]["label"])
|
||||
if not columns[idx].get("hidden"):
|
||||
result[0].append(columns[idx]["label"])
|
||||
|
||||
# build table from result
|
||||
for i, row in enumerate(data.result):
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
"subject",
|
||||
"message",
|
||||
"send_unsubscribe_link",
|
||||
"send_attachements",
|
||||
"send_attachments",
|
||||
"published",
|
||||
"route",
|
||||
"test_the_newsletter",
|
||||
|
|
@ -73,12 +73,6 @@
|
|||
"fieldtype": "Check",
|
||||
"label": "Send Unsubscribe Link"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "send_attachements",
|
||||
"fieldtype": "Check",
|
||||
"label": "Send Attachements"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "published",
|
||||
|
|
@ -127,6 +121,12 @@
|
|||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "send_attachments",
|
||||
"fieldtype": "Check",
|
||||
"label": "Send Attachments"
|
||||
}
|
||||
],
|
||||
"has_web_view": 1,
|
||||
|
|
@ -135,7 +135,7 @@
|
|||
"is_published_field": "published",
|
||||
"links": [],
|
||||
"max_attachments": 3,
|
||||
"modified": "2020-03-02 06:26:51.622521",
|
||||
"modified": "2020-05-12 18:09:40.137138",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Newsletter",
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class Newsletter(WebsiteGenerator):
|
|||
frappe.db.auto_commit_on_many_writes = True
|
||||
|
||||
attachments = []
|
||||
if self.send_attachements:
|
||||
if self.send_attachments:
|
||||
files = frappe.get_all("File", fields=["name"], filters={"attached_to_doctype": "Newsletter",
|
||||
"attached_to_name": self.name}, order_by="creation desc")
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from frappe.utils import split_emails, get_backups_path
|
|||
|
||||
|
||||
def send_email(success, service_name, doctype, email_field, error_status=None):
|
||||
recipients = get_recipients(service_name, email_field)
|
||||
recipients = get_recipients(doctype, email_field)
|
||||
if not recipients:
|
||||
frappe.log_error("No Email Recipient found for {0}".format(service_name),
|
||||
"{0}: Failed to send backup status email".format(service_name))
|
||||
|
|
@ -36,11 +36,11 @@ def send_email(success, service_name, doctype, email_field, error_status=None):
|
|||
frappe.sendmail(recipients=recipients, subject=subject, message=message)
|
||||
|
||||
|
||||
def get_recipients(service_name, email_field):
|
||||
def get_recipients(doctype, email_field):
|
||||
if not frappe.db:
|
||||
frappe.connect()
|
||||
|
||||
return split_emails(frappe.db.get_value(service_name, None, email_field))
|
||||
return split_emails(frappe.db.get_value(doctype, None, email_field))
|
||||
|
||||
|
||||
def get_latest_backup_file(with_files=False):
|
||||
|
|
|
|||
|
|
@ -452,6 +452,7 @@ class Meta(Document):
|
|||
for link in self.links:
|
||||
link.added = False
|
||||
for group in data.transactions:
|
||||
group = frappe._dict(group)
|
||||
# group found
|
||||
if link.group and group.label == link.group:
|
||||
if link.link_doctype not in group.get('items'):
|
||||
|
|
@ -460,7 +461,7 @@ class Meta(Document):
|
|||
|
||||
if not link.added:
|
||||
# group not found, make a new group
|
||||
data.transactions.append(frappe._dict(
|
||||
data.transactions.append(dict(
|
||||
label = link.group,
|
||||
items = [link.link_doctype]
|
||||
))
|
||||
|
|
|
|||
|
|
@ -278,3 +278,4 @@ frappe.patches.v13_0.set_path_for_homepage_in_web_page_view
|
|||
frappe.patches.v13_0.migrate_translation_column_data
|
||||
frappe.patches.v13_0.set_read_times
|
||||
frappe.patches.v13_0.remove_web_view
|
||||
frappe.patches.v13_0.remove_tailwind_from_page_builder
|
||||
|
|
|
|||
13
frappe/patches/v13_0/remove_tailwind_from_page_builder.py
Normal file
13
frappe/patches/v13_0/remove_tailwind_from_page_builder.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("website", "doctype", "web_page_block")
|
||||
# remove unused templates
|
||||
frappe.delete_doc("Web Template", "Navbar with Links on Right", force=1)
|
||||
frappe.delete_doc("Web Template", "Footer Horizontal", force=1)
|
||||
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
{
|
||||
"css/tailwind.css": [
|
||||
"public/tailwind.css"
|
||||
],
|
||||
"css/frappe-web-b4.css": [
|
||||
"public/scss/website.scss",
|
||||
"public/less/indicator.less"
|
||||
|
|
|
|||
|
|
@ -126,27 +126,9 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(row, index) in call.stack">
|
||||
<tr :key="index" @click="showing_traceback = showing_traceback == index ? null : index">
|
||||
<tr :key="index">
|
||||
<td v-for="key in ['filename', 'lineno', 'function']" :key="key">{{ row[key] }}</td>
|
||||
</tr>
|
||||
<tr v-if="showing_traceback == index">
|
||||
<td colspan="4" v-html="row.context"></td>
|
||||
</tr>
|
||||
<tr v-if="showing_traceback == index">
|
||||
<td colspan="4">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr><th>Variable</th><th>Value</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(variable, index) in Object.entries(JSON.parse(row.locals))" :key="index">
|
||||
<td>{{ variable[0] }}</td>
|
||||
<td>{{ variable[1] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -244,7 +226,6 @@ export default {
|
|||
},
|
||||
group_duplicates: false,
|
||||
showing: null,
|
||||
showing_traceback: null,
|
||||
request: {
|
||||
calls: [],
|
||||
},
|
||||
|
|
|
|||
43
frappe/public/scss/base.scss
Normal file
43
frappe/public/scss/base.scss
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: 16px;
|
||||
color: $body-color;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: $font-size-3xl;
|
||||
font-weight: 800;
|
||||
line-height: 1.25;
|
||||
letter-spacing: -0.025em;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
line-height: 2.5rem;
|
||||
font-size: $font-size-4xl;
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
line-height: 1;
|
||||
font-size: $font-size-5xl;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $font-size-xl;
|
||||
font-weight: bold;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
font-size: $font-size-2xl;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
font-size: $font-size-3xl;
|
||||
}
|
||||
}
|
||||
|
||||
117
frappe/public/scss/markdown.scss
Normal file
117
frappe/public/scss/markdown.scss
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
.from-markdown {
|
||||
line-height: 1.625;
|
||||
|
||||
> * + * {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding-left: 2.5rem;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
li > * + * {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
> ul > * + *,
|
||||
> ol > * + * {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
> blockquote {
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: $font-size-sm;
|
||||
font-weight: 500;
|
||||
color: $gray-900;
|
||||
border-left: 4px solid $yellow;
|
||||
background-color: lighten($yellow, 42%);
|
||||
border-top-left-radius: 0.1rem;
|
||||
border-bottom-left-radius: 0.1rem;
|
||||
border-top-right-radius: 0.375rem;
|
||||
border-bottom-right-radius: 0.375rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
blockquote p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h1 + p {
|
||||
max-width: 42rem;
|
||||
margin-top: 0.75rem;
|
||||
font-size: $font-size-base;
|
||||
color: $gray-900;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-top: 1.25rem;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 1rem;
|
||||
margin-top: 3.5rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
font-size: $font-size-xl;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: $font-size-base;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
h6 {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: $font-size-sm;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
tr > td,
|
||||
tr > th {
|
||||
font-size: $font-size-sm;
|
||||
}
|
||||
|
||||
th:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.screenshot {
|
||||
border: 1px solid $gray-400;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
}
|
||||
252
frappe/public/scss/page-builder.scss
Normal file
252
frappe/public/scss/page-builder.scss
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
.hero-subtitle {
|
||||
@extend .lead;
|
||||
max-width: 42rem;
|
||||
}
|
||||
|
||||
.section-description {
|
||||
max-width: 56rem;
|
||||
margin-top: 0.5rem;
|
||||
font-size: $font-size-base;
|
||||
color: $gray-900;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
font-size: $font-size-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.section-image {
|
||||
margin-top: 2rem;
|
||||
border-radius: 0.75rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.section-padding {
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
padding-top: 5rem;
|
||||
padding-bottom: 5rem;
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
padding-top: 8rem;
|
||||
padding-bottom: 8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.section-padding-top {
|
||||
padding-top: 3rem;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
padding-top: 5rem;
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
padding-top: 8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.section-padding-bottom {
|
||||
padding-bottom: 3rem;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
padding-bottom: 5rem;
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
padding-bottom: 8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-with-right-image {
|
||||
position: relative;
|
||||
|
||||
.hero-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-image {
|
||||
width: auto;
|
||||
display: none;
|
||||
object-fit: contain;
|
||||
max-height: 36rem;
|
||||
|
||||
&.contain-image {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
display: block;
|
||||
max-width: 28rem;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
max-width: 32rem;
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
max-width: 42rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
.card-title {
|
||||
color: $black;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
color: $gray-900;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $gray-600;
|
||||
}
|
||||
|
||||
&.card-sm {
|
||||
.card-body {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: $font-size-base;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-text {
|
||||
font-size: $font-size-sm;
|
||||
}
|
||||
}
|
||||
&.card-md {
|
||||
.card-body {
|
||||
padding: 1.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: $font-size-lg;
|
||||
font-weight: 600;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
font-size: $font-size-xl;
|
||||
}
|
||||
}
|
||||
.card-text {
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
}
|
||||
&.card-lg {
|
||||
.card-body {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: $font-size-xl;
|
||||
font-weight: bold;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
font-size: $font-size-2xl;
|
||||
}
|
||||
}
|
||||
|
||||
.card-text {
|
||||
font-size: $font-size-base;
|
||||
|
||||
@include media-breakpoint-up(xl) {
|
||||
font-size: $font-size-lg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
.nav-link {
|
||||
color: $gray-700;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
padding: 1rem 0.5rem;
|
||||
margin-right: 2rem;
|
||||
|
||||
&:hover {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link.active,
|
||||
.nav-item.show .nav-link {
|
||||
color: darken($primary, 5%);
|
||||
background-color: #fff;
|
||||
border-bottom: 2px solid $primary;
|
||||
}
|
||||
}
|
||||
|
||||
.section-markdown > .from-markdown {
|
||||
max-width: 42rem;
|
||||
}
|
||||
|
||||
.section-cta {
|
||||
padding: 3rem 2rem;
|
||||
text-align: center;
|
||||
background-color: lighten($primary, 42%);
|
||||
border-radius: 0.75rem;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
padding-left: 3rem;
|
||||
padding-right: 3rem;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
padding-top: 5rem;
|
||||
padding-bottom: 5rem;
|
||||
}
|
||||
|
||||
.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;
|
||||
margin: 0 auto;
|
||||
margin-top: 0.5rem;
|
||||
font-size: $font-size-base;
|
||||
color: $gray-900;
|
||||
@include media-breakpoint-up(md) {
|
||||
font-size: $font-size-lg;
|
||||
}
|
||||
}
|
||||
.description {
|
||||
max-width: 36rem;
|
||||
margin: 0 auto;
|
||||
margin-top: 0.5rem;
|
||||
font-size: $font-size-xs;
|
||||
color: $gray-900;
|
||||
}
|
||||
}
|
||||
|
||||
.section-cta-container {
|
||||
position: relative;
|
||||
.confetti {
|
||||
position: absolute;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: 99999px;
|
||||
}
|
||||
.confetti-1 {
|
||||
top: 0;
|
||||
margin-top: -0.5rem;
|
||||
background-color: #84e1bc;
|
||||
left: 25%;
|
||||
}
|
||||
.confetti-2 {
|
||||
background-color: #fdba8c;
|
||||
top: 66.67%;
|
||||
right: 16.67%;
|
||||
}
|
||||
.confetti-3 {
|
||||
bottom: 0;
|
||||
margin-bottom: -0.5rem;
|
||||
background-color: #f8b4b4;
|
||||
left: 16.67%;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,14 +8,45 @@ $gray-600: #8d99a6 !default;
|
|||
$gray-700: #495057 !default;
|
||||
$gray-800: #36414c !default;
|
||||
$gray-900: #2e3338 !default;
|
||||
$primary: #5e64ff !default;
|
||||
$primary: #2490ef !default;
|
||||
|
||||
$black: #000 !default;
|
||||
|
||||
$body-color: $gray-800 !default;
|
||||
$text-muted: $gray-600 !default;
|
||||
$border-color: $gray-200 !default;
|
||||
$border-color: $gray-300 !default;
|
||||
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
$font-size-xs: 0.75rem !default;
|
||||
$font-size-sm: 0.875rem !default;
|
||||
$font-size-base: 1rem !default;
|
||||
$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-5xl: 3rem !default;
|
||||
$font-size-6xl: 4rem !default;
|
||||
|
||||
$btn-padding-y-lg: 1rem !default;
|
||||
$btn-padding-x-lg: 2.5rem !default;
|
||||
$btn-font-size-lg: 1.125rem !default;
|
||||
$btn-line-height-lg: 1 !default;
|
||||
$btn-border-radius-lg: 0.5rem !default;
|
||||
$btn-border-radius: 0.375rem !default;
|
||||
$btn-font-size: $font-size-sm;
|
||||
$btn-padding-x: 1rem !default;
|
||||
$btn-padding-y: 0.5rem !default;
|
||||
$btn-font-weight: 500 !default;
|
||||
|
||||
$navbar-nav-link-padding-x: 1rem !default;
|
||||
$navbar-padding-y: 1rem;
|
||||
$card-border-radius: 0.75rem !default;
|
||||
$card-spacer-y: 1rem !default;
|
||||
|
||||
$dropdown-font-size: $font-size-sm !default;
|
||||
$dropdown-border-radius: 0.375rem !default;
|
||||
$dropdown-item-padding-y: 0.5rem !default;
|
||||
$dropdown-item-padding-x: 0.5rem !default;
|
||||
|
||||
@import '~bootstrap/scss/functions';
|
||||
@import '~bootstrap/scss/variables';
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ img:after {
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 3rem;
|
||||
font-size: $font-size-5xl;
|
||||
color: $gray-300;
|
||||
background: $light;
|
||||
}
|
||||
|
|
@ -85,4 +85,4 @@ img:after {
|
|||
|
||||
.object-fit-cover {
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,71 @@
|
|||
@import "variables";
|
||||
@import "frappe/public/css/font-awesome";
|
||||
@import "~bootstrap/scss/bootstrap";
|
||||
@import "multilevel-dropdown";
|
||||
@import "website-image";
|
||||
@import 'variables';
|
||||
@import 'frappe/public/css/font-awesome';
|
||||
@import '~bootstrap/scss/bootstrap';
|
||||
@import 'base';
|
||||
@import 'multilevel-dropdown';
|
||||
@import 'website-image';
|
||||
@import 'page-builder';
|
||||
@import 'markdown';
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
.container {
|
||||
padding-left: 1.25rem;
|
||||
padding-right: 1.25rem;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 16px;
|
||||
|
||||
> div {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// make navbar padding consistent with the page
|
||||
.navbar {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
.container {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
.container {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
.container {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl) {
|
||||
.container {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-light {
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.navbar-light .navbar-nav .nav-link {
|
||||
color: $gray-900;
|
||||
font-size: $font-size-sm;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover,
|
||||
&:focus, &.active {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
border-radius: $dropdown-border-radius;
|
||||
}
|
||||
|
||||
.navbar.bg-dark {
|
||||
.dropdown-menu {
|
||||
font-size: .75rem;
|
||||
font-size: 0.75rem;
|
||||
background-color: $dark;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
|
@ -64,7 +93,6 @@ footer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.input-dark {
|
||||
background-color: $dark;
|
||||
border-color: darken($primary, 40%);
|
||||
|
|
@ -72,25 +100,21 @@ footer {
|
|||
}
|
||||
|
||||
.breadcrumb {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
background-color: white;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
a.card {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
@extend .d-none;
|
||||
}
|
||||
|
||||
.hide-control {
|
||||
@extend .d-none;
|
||||
@extend .d-none;
|
||||
}
|
||||
|
||||
.text-underline {
|
||||
|
|
@ -101,10 +125,49 @@ img {
|
|||
color: #d1d8dd !important;
|
||||
}
|
||||
|
||||
// footer
|
||||
|
||||
.web-footer {
|
||||
padding: 5rem 0;
|
||||
min-height: 140px;
|
||||
border-top: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.footer-logo {
|
||||
width: 5rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.footer-link, .footer-child-item a {
|
||||
font-weight: 500;
|
||||
color: $gray-900;
|
||||
|
||||
&:hover {
|
||||
color: $primary;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-col-left, .footer-col-right {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.footer-col-right {
|
||||
@include media-breakpoint-up(sm) {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-col-left .footer-link {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.footer-col-right .footer-link {
|
||||
margin-right: 1rem;
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-right: 0;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-group-label {
|
||||
|
|
@ -112,41 +175,75 @@ img {
|
|||
}
|
||||
|
||||
.footer-parent-item {
|
||||
margin-bottom: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.footer-info {
|
||||
border-top: 1px solid $border-color;
|
||||
color: $text-muted;
|
||||
font-size: $font-size-sm;
|
||||
}
|
||||
|
||||
.no-underline {
|
||||
text-decoration: none !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
font-size: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
h4.modal-title {
|
||||
font-size: 1em;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h5.modal-title {
|
||||
margin: 0px !important;
|
||||
margin: 0px !important;
|
||||
}
|
||||
|
||||
.col-xs-1 { @extend .col-1; }
|
||||
.col-xs-2 { @extend .col-2; }
|
||||
.col-xs-3 { @extend .col-3; }
|
||||
.col-xs-4 { @extend .col-4; }
|
||||
.col-xs-5 { @extend .col-5; }
|
||||
.col-xs-6 { @extend .col-6; }
|
||||
.col-xs-7 { @extend .col-7; }
|
||||
.col-xs-8 { @extend .col-8; }
|
||||
.col-xs-9 { @extend .col-9; }
|
||||
.col-xs-10 { @extend .col-10; }
|
||||
.col-xs-11 { @extend .col-11; }
|
||||
.col-xs-12 { @extend .col-12; }
|
||||
.col-xs-1 {
|
||||
@extend .col-1;
|
||||
}
|
||||
.col-xs-2 {
|
||||
@extend .col-2;
|
||||
}
|
||||
.col-xs-3 {
|
||||
@extend .col-3;
|
||||
}
|
||||
.col-xs-4 {
|
||||
@extend .col-4;
|
||||
}
|
||||
.col-xs-5 {
|
||||
@extend .col-5;
|
||||
}
|
||||
.col-xs-6 {
|
||||
@extend .col-6;
|
||||
}
|
||||
.col-xs-7 {
|
||||
@extend .col-7;
|
||||
}
|
||||
.col-xs-8 {
|
||||
@extend .col-8;
|
||||
}
|
||||
.col-xs-9 {
|
||||
@extend .col-9;
|
||||
}
|
||||
.col-xs-10 {
|
||||
@extend .col-10;
|
||||
}
|
||||
.col-xs-11 {
|
||||
@extend .col-11;
|
||||
}
|
||||
.col-xs-12 {
|
||||
@extend .col-12;
|
||||
}
|
||||
|
||||
.btn-default { @extend .btn-light; }
|
||||
.btn-default {
|
||||
@extend .btn-light;
|
||||
}
|
||||
|
||||
.btn-xs { @extend .btn-sm; }
|
||||
.btn-xs {
|
||||
@extend .btn-sm;
|
||||
}
|
||||
|
||||
.hidden-xs {
|
||||
@extend .d-none;
|
||||
|
|
@ -171,3 +268,29 @@ h5.modal-title {
|
|||
.pull-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.btn-primary-light {
|
||||
$primary-light: lighten($primary, 42%);
|
||||
@include button-variant(
|
||||
$background: $primary-light,
|
||||
$border: $primary-light,
|
||||
$hover-background: lighten($primary-light, 1%),
|
||||
$hover-border: $primary-light,
|
||||
$active-background: lighten($primary-light, 1%),
|
||||
$active-border: darken($primary-light, 12.5%)
|
||||
);
|
||||
|
||||
color: darken($primary, 5%);
|
||||
&:hover {
|
||||
color: darken($primary, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.image-with-blur {
|
||||
transition: filter 300ms ease-in-out;
|
||||
filter: blur(1.5rem);
|
||||
}
|
||||
|
||||
.image-loaded {
|
||||
filter: blur(0rem);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,141 +0,0 @@
|
|||
@tailwind base;
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply antialiased;
|
||||
@apply text-black;
|
||||
}
|
||||
|
||||
@tailwind components;
|
||||
|
||||
details.hide-summary-arrow summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.from-markdown {
|
||||
@apply leading-relaxed;
|
||||
|
||||
> * + * {
|
||||
@apply mt-4;
|
||||
}
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
@apply pl-10;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-disc;
|
||||
}
|
||||
|
||||
ol {
|
||||
@apply list-decimal;
|
||||
}
|
||||
|
||||
li > * + * {
|
||||
@apply mt-4;
|
||||
}
|
||||
|
||||
> ul > * + *,
|
||||
> ol > * + * {
|
||||
@apply mt-4;
|
||||
}
|
||||
|
||||
> blockquote {
|
||||
@apply px-4 py-3 text-sm font-medium text-gray-900 border border-gray-400 rounded-md bg-gray-50;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply mt-16 mb-4 text-3xl font-extrabold leading-tight tracking-tight;
|
||||
@screen sm {
|
||||
@apply text-4xl leading-10;
|
||||
}
|
||||
@screen xl {
|
||||
@apply text-5xl leading-none;
|
||||
}
|
||||
}
|
||||
|
||||
h1 + p {
|
||||
@apply max-w-2xl mt-3 text-base text-gray-900;
|
||||
|
||||
@screen sm {
|
||||
@apply mt-5 text-lg;
|
||||
}
|
||||
@screen md {
|
||||
@apply mt-5 text-xl;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply mb-4 text-2xl font-bold leading-tight mt-14;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply mt-12 mb-4 text-xl font-semibold leading-tight;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply mt-10 mb-4 text-lg font-semibold leading-tight;
|
||||
}
|
||||
|
||||
h5 {
|
||||
@apply mt-8 mb-4 text-base font-semibold leading-tight;
|
||||
}
|
||||
|
||||
h6 {
|
||||
@apply mt-6 mb-4 text-sm font-semibold leading-tight;
|
||||
}
|
||||
|
||||
> a,
|
||||
> p a,
|
||||
> ul li a,
|
||||
> ol li a {
|
||||
@apply border-b border-gray-800;
|
||||
&:hover {
|
||||
@apply text-gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
@apply w-full my-8 border-t;
|
||||
}
|
||||
|
||||
tbody {
|
||||
@apply border-t;
|
||||
}
|
||||
|
||||
tr > td,
|
||||
tr > th {
|
||||
@apply py-4 pr-6 text-sm leading-6 text-left border-b;
|
||||
}
|
||||
|
||||
th:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.screenshot {
|
||||
@apply border border-gray-400 rounded-md;
|
||||
}
|
||||
}
|
||||
|
||||
@tailwind utilities;
|
||||
|
||||
.blur-none {
|
||||
filter: blur(0rem);
|
||||
}
|
||||
|
||||
.blur-sm {
|
||||
filter: blur(1rem);
|
||||
}
|
||||
|
||||
.blur-md {
|
||||
filter: blur(1.5rem);
|
||||
}
|
||||
|
||||
.blur-lg {
|
||||
filter: blur(2rem);
|
||||
}
|
||||
|
|
@ -9,12 +9,8 @@ import inspect
|
|||
import json
|
||||
import re
|
||||
import time
|
||||
import traceback
|
||||
import frappe
|
||||
import sqlparse
|
||||
from pygments import highlight
|
||||
from pygments.lexers import PythonLexer
|
||||
from pygments.formatters import HtmlFormatter
|
||||
|
||||
from frappe import _
|
||||
|
||||
|
|
@ -30,7 +26,7 @@ def sql(*args, **kwargs):
|
|||
|
||||
stack = list(get_current_stack_frames())
|
||||
|
||||
if frappe.db.db_type == 'postgres':
|
||||
if frappe.db.db_type == "postgres":
|
||||
query = frappe.db._cursor.query
|
||||
else:
|
||||
query = frappe.db._cursor._executed
|
||||
|
|
@ -65,9 +61,6 @@ def get_current_stack_frames():
|
|||
"filename": re.sub(".*/apps/", "", filename),
|
||||
"lineno": lineno,
|
||||
"function": function,
|
||||
"context": "".join(context),
|
||||
"index": index,
|
||||
"locals": json.dumps(frame.f_locals, skipkeys=True, default=str)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -83,7 +76,7 @@ def dump():
|
|||
frappe.local._recorder.dump()
|
||||
|
||||
|
||||
class Recorder():
|
||||
class Recorder:
|
||||
def __init__(self):
|
||||
self.uuid = frappe.generate_hash(length=10)
|
||||
self.time = datetime.datetime.now()
|
||||
|
|
@ -105,12 +98,18 @@ class Recorder():
|
|||
"cmd": self.cmd,
|
||||
"time": self.time,
|
||||
"queries": len(self.calls),
|
||||
"time_queries": float("{:0.3f}".format(sum(call["duration"] for call in self.calls))),
|
||||
"duration": float("{:0.3f}".format((datetime.datetime.now() - self.time).total_seconds() * 1000)),
|
||||
"time_queries": float(
|
||||
"{:0.3f}".format(sum(call["duration"] for call in self.calls))
|
||||
),
|
||||
"duration": float(
|
||||
"{:0.3f}".format((datetime.datetime.now() - self.time).total_seconds() * 1000)
|
||||
),
|
||||
"method": self.method,
|
||||
}
|
||||
frappe.cache().hset(RECORDER_REQUEST_SPARSE_HASH, self.uuid, request_data)
|
||||
frappe.publish_realtime(event="recorder-dump-event", message=json.dumps(request_data, default=str))
|
||||
frappe.publish_realtime(
|
||||
event="recorder-dump-event", message=json.dumps(request_data, default=str)
|
||||
)
|
||||
|
||||
self.mark_duplicates()
|
||||
|
||||
|
|
@ -137,6 +136,7 @@ def do_not_record(function):
|
|||
del frappe.local._recorder
|
||||
frappe.db.sql = frappe.db._sql
|
||||
return function(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
|
|
@ -145,6 +145,7 @@ def administrator_only(function):
|
|||
if frappe.session.user != "Administrator":
|
||||
frappe.throw(_("Only Administrator is allowed to use Recorder"))
|
||||
return function(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
|
|
@ -175,11 +176,6 @@ def stop(*args, **kwargs):
|
|||
def get(uuid=None, *args, **kwargs):
|
||||
if uuid:
|
||||
result = frappe.cache().hget(RECORDER_REQUEST_HASH, uuid)
|
||||
lexer = PythonLexer(tabsize=4)
|
||||
for call in result["calls"]:
|
||||
for stack in call["stack"]:
|
||||
formatter = HtmlFormatter(noclasses=True, hl_lines=[stack["index"] + 1])
|
||||
stack["context"] = highlight(stack["context"], lexer, formatter)
|
||||
else:
|
||||
result = list(frappe.cache().hgetall(RECORDER_REQUEST_SPARSE_HASH).values())
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -25,26 +25,10 @@
|
|||
{{ head_html or "" }}
|
||||
{%- endif %}
|
||||
|
||||
{%- if theme.based_on == 'Bootstrap 4' or doctype != 'Web Page' -%}
|
||||
{%- if theme.theme_url -%}
|
||||
<link type="text/css" rel="stylesheet" href="{{ theme.theme_url }}">
|
||||
{%- else -%}
|
||||
<link type="text/css" rel="stylesheet" href="/assets/css/frappe-web-b4.css">
|
||||
{%- endif -%}
|
||||
{% else %}
|
||||
{%- if developer_mode -%}
|
||||
<!-- load the full list of tailwind classes in development -->
|
||||
<link type="text/css" rel="stylesheet" href="/assets/css/tailwind.css">
|
||||
{%- else -%}
|
||||
<!-- load tree-shaken classes in production -->
|
||||
<!-- container for processed tailwind styles -->
|
||||
<!-- tailwind-styles -->
|
||||
{% endif %}
|
||||
{%- if theme.theme_css -%}
|
||||
<style>
|
||||
{{ theme.theme_css }}
|
||||
</style>
|
||||
{%- endif -%}
|
||||
{%- if theme.name != 'Standard' -%}
|
||||
<link type="text/css" rel="stylesheet" href="{{ theme.theme_url }}">
|
||||
{%- else -%}
|
||||
<link type="text/css" rel="stylesheet" href="/assets/css/frappe-web-b4.css">
|
||||
{%- endif -%}
|
||||
|
||||
{%- for link in web_include_css %}
|
||||
|
|
@ -65,7 +49,7 @@
|
|||
frappe.ready_events.push(fn);
|
||||
}
|
||||
window.dev_server = {{ dev_server }};
|
||||
window.socketio_port = {{ frappe.socketio_port }};
|
||||
window.socketio_port = {{ (frappe.socketio_port or 'null') }};
|
||||
</script>
|
||||
</head>
|
||||
<body frappe-session-status="{{ 'logged-in' if frappe.session.user != 'Guest' else 'logged-out'}}" data-path="{{ path | e }}" {%- if template and template.endswith('.md') %} frappe-content-type="markdown" {% endif -%}>
|
||||
|
|
@ -78,11 +62,7 @@
|
|||
{%- endblock -%}
|
||||
|
||||
{%- block navbar -%}
|
||||
{%- if navbar_content -%}
|
||||
{{ navbar_content }}
|
||||
{%- else -%}
|
||||
{% include "templates/includes/navbar/navbar.html" %}
|
||||
{%- endif -%}
|
||||
{% include "templates/includes/navbar/navbar.html" %}
|
||||
{%- endblock -%}
|
||||
|
||||
{% block content %}
|
||||
|
|
@ -90,11 +70,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{%- block footer -%}
|
||||
{%- if footer_content -%}
|
||||
{{ footer_content }}
|
||||
{%- else -%}
|
||||
{% include "templates/includes/footer/footer.html" %}
|
||||
{%- endif -%}
|
||||
{% include "templates/includes/footer/footer.html" %}
|
||||
{%- endblock -%}
|
||||
|
||||
{% block base_scripts %}
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
name: "button"
|
||||
variant: "secondary"
|
||||
size: "small"
|
||||
disabled: 0
|
||||
url: null
|
||||
---
|
||||
|
||||
{%- set static_classes = "border inline-flex justify-center items-center focus:outline-none font-medium transition duration-150 ease-in-out" -%}
|
||||
{%- set dynamic_classes = {
|
||||
"px-4 py-2 text-sm leading-5 rounded-md": size == "small",
|
||||
"px-8 py-3 sm:px-10 sm:py-4 text-base sm:text-lg leading-6 rounded-lg": size == "large",
|
||||
"opacity-50 cursor-not-allowed pointer-events-none": disabled,
|
||||
"bg-primary-500 border-transparent hover:bg-primary-400 text-white focus:shadow-outline-primary focus:border-primary-600":
|
||||
variant == "primary",
|
||||
"bg-primary-100 border-transparent text-primary-700 hover:text-primary-600 hover:bg-primary-50 focus:shadow-outline-primary focus:border-primary-300":
|
||||
variant == "secondary",
|
||||
"bg-red-500 border-transparent hover:bg-red-400 text-white focus:shadow-outline-red focus:border-red-700":
|
||||
variant == "danger"
|
||||
}
|
||||
-%}
|
||||
{%- set html_tag = "a" if url else "button" -%}
|
||||
|
||||
<{{html_tag}}
|
||||
class="{{ resolve_class([static_classes, dynamic_classes, class]) }}"
|
||||
{{ 'disabled' if disabled else '' }}
|
||||
{{ ('href="' + url + '"') if url else '' }}>
|
||||
{{ label }}
|
||||
</{{html_tag}}>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
<details class="relative inline-block text-left dropdown hide-summary-arrow">
|
||||
<summary class="block cursor-pointer focus:outline-none">
|
||||
<span class="inline-flex items-center justify-center text-gray-800 hover:text-gray-900">
|
||||
{{ label }}
|
||||
<svg class="w-5 h-5 ml-2 -mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
</span>
|
||||
</summary>
|
||||
<div
|
||||
class="absolute right-0 w-56 mt-2 origin-top-right rounded-md shadow-lg">
|
||||
<div class="bg-white rounded-md shadow-xs">
|
||||
<div class="py-1">
|
||||
{%- for item in items -%}
|
||||
<a href="{{ item.link or item.url }}"
|
||||
class="block px-4 py-2 text-sm leading-5 text-gray-800 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">
|
||||
{{ item.label }}
|
||||
</a>
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<a href="{{ url }}" class="font-medium text-gray-900 hover:text-primary-500">
|
||||
{{ label }}
|
||||
</a>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
{%- for web_block in web_blocks -%}
|
||||
{{ c('web_block', web_block=web_block, htmltag=htmltag) }}
|
||||
{%- endfor -%}
|
||||
|
|
@ -1,45 +1,46 @@
|
|||
{%- if theme.based_on == 'Bootstrap 4' or doctype != 'Web Page' -%}
|
||||
<footer class="web-footer">
|
||||
<section class="footer-links">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="text-left col-sm-6">
|
||||
{% if footer_items -%}
|
||||
<div class="row">
|
||||
{% include "templates/includes/footer/footer_items.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="text-right col-sm-6">
|
||||
{% block extension %}
|
||||
{% include "templates/includes/footer/footer_extension.html" %}
|
||||
{% endblock %}
|
||||
<div class="container">
|
||||
{%- if footer_logo -%}
|
||||
<div>
|
||||
<img src="{{ footer_logo }}" alt="Footer Logo" class="footer-logo">
|
||||
</div>
|
||||
{%- endif -%}
|
||||
<div class="row">
|
||||
<div class="text-left col-sm-6">
|
||||
{% if footer_items -%}
|
||||
<div class="row">
|
||||
{% include ["templates/includes/footer/footer_grouped_links.html", "templates/includes/footer/footer_items.html"] %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="mt-5 row footer-bottom-line">
|
||||
<div class="text-muted small col-sm-6 col-12">
|
||||
|
||||
<div class="text-right col-sm-6">
|
||||
{% block extension %}
|
||||
{% include "templates/includes/footer/footer_extension.html" %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "templates/includes/footer/footer_links.html" %}
|
||||
|
||||
<div class="footer-info">
|
||||
<div class="row">
|
||||
<div class="footer-col-left col-sm-6 col-12">
|
||||
{% if copyright %}
|
||||
© {{ copyright }}
|
||||
© {{ copyright }}
|
||||
{% endif %}
|
||||
{% if footer_address %}
|
||||
{% if copyright %}<br>{% endif %}
|
||||
{{ footer_address }}
|
||||
{% if copyright %}<br>{% endif %}
|
||||
{{ footer_address }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{# powered #}
|
||||
<div class="text-right text-muted small col-sm-6 col-12 footer-powered">
|
||||
<div class="footer-col-right col-sm-6 col-12 footer-powered">
|
||||
{% block powered %}
|
||||
{% include "templates/includes/footer/footer_powered.html" %}
|
||||
{% include "templates/includes/footer/footer_powered.html" %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{%- else -%}
|
||||
<footer>
|
||||
{{ c('web_blocks', web_blocks=theme.footer) }}
|
||||
</footer>
|
||||
{%- endif -%}
|
||||
|
|
|
|||
28
frappe/templates/includes/footer/footer_grouped_links.html
Normal file
28
frappe/templates/includes/footer/footer_grouped_links.html
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{% for page in footer_items if page.child_items %}
|
||||
<div class="col footer-group">
|
||||
<div data-label="{{ page.label }}">
|
||||
<span>
|
||||
<div class="footer-group-label footer-parent-item">
|
||||
{%- if page.icon -%}
|
||||
<img src="{{ page.icon }}" alt="{{ page.label }}">
|
||||
{%- else -%}
|
||||
{{ page.label }}
|
||||
{%- endif -%}
|
||||
</div>
|
||||
</span>
|
||||
<ul class="list-unstyled">
|
||||
{%- for child in page.child_items -%}
|
||||
<li class="mt-2 footer-child-item" data-label='{{ child.label }}'>
|
||||
<a href="{{ child.url | abs_url }}" {% if child.target %} target="_blank" {% endif %}>
|
||||
{%- if child.icon -%}
|
||||
<img src="{{ child.icon }}" alt="{{ child.label }}">
|
||||
{%- else -%}
|
||||
{{ child.label }}
|
||||
{%- endif -%}
|
||||
</a>
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
27
frappe/templates/includes/footer/footer_links.html
Normal file
27
frappe/templates/includes/footer/footer_links.html
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{% macro footer_link(item) %}
|
||||
<a href="{{ item.url | abs_url }}" class="footer-link">
|
||||
{%- if item.icon -%}
|
||||
<img src="{{ item.icon }}" alt="{{ item.label }}">
|
||||
{%- else -%}
|
||||
{{ item.label }}
|
||||
{%- endif -%}
|
||||
</a>
|
||||
{% endmacro %}
|
||||
|
||||
{% if footer_items -%}
|
||||
<div class="footer-links">
|
||||
<div class="row">
|
||||
<div class="footer-col-left col-sm-6">
|
||||
{% for item in footer_items if item.label and not (item.parent_label or item.child_items) and not item.right %}
|
||||
{{ footer_link(item) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="footer-col-right col-sm-6">
|
||||
{% for item in footer_items if item.label and not (item.parent_label or item.child_items) and item.right %}
|
||||
{{ footer_link(item) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{%- set res = frappe.utils.get_thumbnail_base64_for_image(src) if src else false -%}
|
||||
{%- if res and res['base64'].startswith('data:') -%}
|
||||
<img src="{{ res['base64'] }}" class="blur-md transition-all duration-300 ease-in-out {{ resolve_class(class) }}"
|
||||
<img src="{{ res['base64'] }}" class="image-with-blur {{ resolve_class(class) }}"
|
||||
alt="{{ alt or '' }}" width="{{ res['width'] }}" height="{{ res['height'] }}" data-src="{{ src or '' }}" />
|
||||
{%- else -%}
|
||||
<img src="{{ src or '' }}" class="{{ resolve_class(class) }}" alt="{{ alt or '' }}" />
|
||||
|
|
@ -18,8 +18,7 @@
|
|||
|
||||
img.onload = function () {
|
||||
image.src = image_source;
|
||||
image.classList.remove('blur-md');
|
||||
image.classList.add('blur-none');
|
||||
image.classList.add('image-loaded');
|
||||
};
|
||||
|
||||
if (image_source) {
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
{%- if theme.based_on == 'Bootstrap 4' or doctype != 'Web Page' -%}
|
||||
<nav class="bg-white shadow-sm navbar navbar-light navbar-expand-lg sticky-top">
|
||||
<nav class="navbar navbar-light navbar-expand-lg">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ url_prefix }}{{ home_page or "/" }}">
|
||||
<span>{{ brand_html or (frappe.get_hooks("brand_html") or [_("Home")])[0] }}</span>
|
||||
|
|
@ -18,8 +17,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{%- else -%}
|
||||
<header>
|
||||
{{ c('web_blocks', web_blocks=theme.navbar, htmltag='div') }}
|
||||
</header>
|
||||
{%- endif -%}
|
||||
|
|
|
|||
|
|
@ -2,24 +2,27 @@
|
|||
{% if item.child_items %}
|
||||
|
||||
{% if parent %}
|
||||
|
||||
{%- set dropdown_id = 'id-' + frappe.utils.generate_hash('Dropdown', 12) -%}
|
||||
<li class="nav-item dropdown {% if submenu %} dropdown-submenu {% endif %}">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
|
||||
<a class="nav-link dropdown-toggle" href="#" id="{{ dropdown_id }}" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ item.label }}
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<ul class="dropdown-menu" aria-labelledby="{{ dropdown_id }}">
|
||||
{% for child in item.child_items %}
|
||||
{{ render_item(child, True) }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
{%- set dropdown_id = 'id-' + frappe.utils.generate_hash('Dropdown', 12) -%}
|
||||
<li class="dropdown {% if submenu %} dropdown-submenu {% endif %}">
|
||||
<a class="dropdown-item dropdown-toggle" href="#" id="navbarDropdown" role="button"
|
||||
<a class="dropdown-item dropdown-toggle" href="#" id="{{ dropdown_id }}" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ item.label }}
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<ul class="dropdown-menu" aria-labelledby="{{ dropdown_id }}">
|
||||
{% for child in item.child_items %}
|
||||
{{ render_item(child, True) }}
|
||||
{% endfor %}
|
||||
|
|
@ -47,7 +50,7 @@
|
|||
{% endmacro %}
|
||||
|
||||
{% if top_bar_items -%}
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<ul class="mr-auto navbar-nav">
|
||||
{%- for item in top_bar_items -%}
|
||||
{% if not item.parent_label and not item.right -%}
|
||||
{{ render_item(item, parent=True) }}
|
||||
|
|
@ -55,7 +58,7 @@
|
|||
{%- endfor %}
|
||||
</ul>
|
||||
{%- endif %}
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<ul class="ml-auto navbar-nav">
|
||||
{%- for item in top_bar_items -%}
|
||||
{% if not item.parent_label and item.right -%}
|
||||
{{ render_item(item, parent=True) }}
|
||||
|
|
@ -84,4 +87,10 @@
|
|||
|
||||
{% include "templates/includes/navbar/navbar_search.html" %}
|
||||
{% include "templates/includes/navbar/navbar_login.html" %}
|
||||
|
||||
</ul>
|
||||
{%- if call_to_action -%}
|
||||
<a class="btn btn-primary" href="{{ call_to_action_url | abs_url }}">
|
||||
{{ call_to_action }}
|
||||
</a>
|
||||
{%- endif -%}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
{%- set htmltag = htmltag or 'section' -%}
|
||||
{%- set classes = resolve_class([
|
||||
{
|
||||
'py-12 sm:py-20 xl:py-32': web_block.add_padding,
|
||||
'bg-gray-100': web_block.add_shade,
|
||||
'section-padding-top': web_block.add_top_padding,
|
||||
'section-padding-bottom': web_block.add_bottom_padding,
|
||||
'bg-light': web_block.add_shade,
|
||||
},
|
||||
web_block.css_class
|
||||
]) -%}
|
||||
|
||||
{%- if not web_block.hide_block -%}
|
||||
<{{htmltag}} class="{{ classes }}" data-section-idx="{{ web_block.idx | e }}"
|
||||
<section class="section {{ classes }}" data-section-idx="{{ web_block.idx | e }}"
|
||||
data-section-template="{{ web_block.web_template | e }}">
|
||||
{%- if web_block.add_container -%}
|
||||
<div class="container">
|
||||
|
|
@ -17,5 +17,5 @@
|
|||
{%- if web_block.add_container -%}
|
||||
</div>
|
||||
{%- endif -%}
|
||||
</{{htmltag}}>
|
||||
</section>
|
||||
{%- endif -%}
|
||||
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
{%- if theme.based_on == 'Bootstrap 4' or doctype != 'Web Page' -%}
|
||||
|
||||
{% macro main_content() %}
|
||||
<div class="page-content-wrapper">
|
||||
<!-- breadcrumbs -->
|
||||
|
|
@ -46,18 +44,18 @@
|
|||
|
||||
{% macro container_attributes() -%}
|
||||
id="page-{{ name or route | e }}" data-path="{{ pathname | e }}"
|
||||
{%- if page_or_generator=="Generator" %}source-type="Generator" data-doctype="{{ doctype }}"{%- endif %}
|
||||
{%- if source_content_type %}source-content-type="{{ source_content_type }}"{%- endif %}
|
||||
{%- if page_or_generator=="Generator" %}source-type="Generator" data-doctype="{{ doctype }}"{%- endif %}
|
||||
{%- if source_content_type %}source-content-type="{{ source_content_type }}"{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% if show_sidebar %}
|
||||
<div class="container">
|
||||
<div class="row" {{ container_attributes() }}>
|
||||
<div class="pt-4 col-sm-2 border-right sidebar-column d-none d-sm-block">
|
||||
{% block page_sidebar %}
|
||||
{% include "templates/includes/web_sidebar.html" %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="pt-4 col-sm-2 border-right sidebar-column d-none d-sm-block">
|
||||
{% block page_sidebar %}
|
||||
{% include "templates/includes/web_sidebar.html" %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="col-sm-10 main-column">
|
||||
{{ main_content() }}
|
||||
</div>
|
||||
|
|
@ -69,10 +67,4 @@ id="page-{{ name or route | e }}" data-path="{{ pathname | e }}"
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{%- else -%}
|
||||
<main>
|
||||
{{ page_content() }}
|
||||
</main>
|
||||
{%- endif -%}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from __future__ import unicode_literals
|
|||
import frappe
|
||||
from frappe import _
|
||||
from functools import wraps
|
||||
from frappe.utils import add_to_date, get_link_to_form
|
||||
from frappe.utils import add_to_date, cint, get_link_to_form
|
||||
from frappe.modules.import_file import import_doc
|
||||
|
||||
|
||||
|
|
@ -75,6 +75,8 @@ def get_from_date_from_timespan(to_date, timespan):
|
|||
|
||||
def sync_dashboards(app=None):
|
||||
"""Import, overwrite fixtures from `[app]/fixtures`"""
|
||||
if not cint(frappe.db.get_single_value('System Settings', 'setup_complete')):
|
||||
return
|
||||
if app:
|
||||
apps = [app]
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@ DATE_FORMAT = "%Y-%m-%d"
|
|||
TIME_FORMAT = "%H:%M:%S.%f"
|
||||
DATETIME_FORMAT = DATE_FORMAT + " " + TIME_FORMAT
|
||||
|
||||
|
||||
def is_invalid_date_string(date_string):
|
||||
# dateutil parser does not agree with dates like "0001-01-01" or "0000-00-00"
|
||||
return (not date_string) or (date_string or "").startswith(("0001-01-01", "0000-00-00"))
|
||||
|
||||
# datetime functions
|
||||
def getdate(string_date=None):
|
||||
"""
|
||||
|
|
@ -36,9 +41,9 @@ def getdate(string_date=None):
|
|||
elif isinstance(string_date, datetime.date):
|
||||
return string_date
|
||||
|
||||
# dateutil parser does not agree with dates like 0001-01-01
|
||||
if not string_date or string_date=="0001-01-01":
|
||||
if is_invalid_date_string(string_date):
|
||||
return None
|
||||
|
||||
return parser.parse(string_date).date()
|
||||
|
||||
def get_datetime(datetime_str=None):
|
||||
|
|
@ -54,8 +59,7 @@ def get_datetime(datetime_str=None):
|
|||
elif isinstance(datetime_str, datetime.date):
|
||||
return datetime.datetime.combine(datetime_str, datetime.time())
|
||||
|
||||
# dateutil parser does not agree with dates like "0001-01-01" or "0000-00-00"
|
||||
if not datetime_str or (datetime_str or "").startswith(("0001-01-01", "0000-00-00")):
|
||||
if is_invalid_date_string(datetime_str):
|
||||
return None
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ def get_jenv():
|
|||
jenv.globals.update(get_safe_globals())
|
||||
jenv.globals.update(get_jenv_customization('methods'))
|
||||
jenv.globals.update({
|
||||
'component': component,
|
||||
'c': component,
|
||||
'resolve_class': resolve_class,
|
||||
'inspect': inspect
|
||||
})
|
||||
|
|
@ -166,29 +164,6 @@ def get_jenv_customization(customization_type):
|
|||
return out
|
||||
|
||||
|
||||
def component(name, **kwargs):
|
||||
from jinja2 import TemplateNotFound
|
||||
|
||||
template_name = 'templates/components/' + name + '.html'
|
||||
jenv = get_jenv()
|
||||
|
||||
try:
|
||||
source = jenv.loader.get_source(jenv, template_name)[0]
|
||||
except TemplateNotFound:
|
||||
return '<pre>Component "{0}" not found</pre>'.format(name)
|
||||
|
||||
attributes, html = parse_front_matter_attrs_and_html(source)
|
||||
context = {}
|
||||
context.update(attributes)
|
||||
context.update(kwargs)
|
||||
|
||||
if 'class' in context:
|
||||
context['class'] = resolve_class(context['class'])
|
||||
else:
|
||||
context['class'] = ''
|
||||
|
||||
return get_jenv().from_string(html).render(context)
|
||||
|
||||
def resolve_class(classes):
|
||||
import frappe
|
||||
|
||||
|
|
@ -206,21 +181,6 @@ def resolve_class(classes):
|
|||
|
||||
return classes
|
||||
|
||||
def parse_front_matter_attrs_and_html(source):
|
||||
from frappe.website.router import get_frontmatter
|
||||
|
||||
html = source
|
||||
attributes = {}
|
||||
|
||||
if not source.startswith('---'):
|
||||
return attributes, html
|
||||
|
||||
res = get_frontmatter(source)
|
||||
if res['attributes']:
|
||||
attributes = res['attributes']
|
||||
html = res['body']
|
||||
|
||||
return attributes, html
|
||||
|
||||
def inspect(var, render=True):
|
||||
context = { "var": var }
|
||||
|
|
|
|||
|
|
@ -1,167 +1,79 @@
|
|||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2013-02-22 01:28:08",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Other",
|
||||
"editable_grid": 1,
|
||||
"actions": [],
|
||||
"creation": "2013-02-22 01:28:08",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Other",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"label",
|
||||
"url",
|
||||
"target",
|
||||
"right",
|
||||
"column_break_5",
|
||||
"parent_label",
|
||||
"icon"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "label",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Label",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "120px",
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"fieldname": "label",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Label",
|
||||
"print_width": "120px",
|
||||
"reqd": 1,
|
||||
"width": "120px"
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"description": "If you set this, this Item will come in a drop-down under the selected parent.",
|
||||
"fieldname": "parent_label",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Parent Label",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"description": "If you set this, this Item will come in a drop-down under the selected parent.",
|
||||
"fieldname": "parent_label",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Parent Label"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"description": "Link to the page you want to open. Leave blank if you want to make it a group parent.",
|
||||
"fieldname": "url",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "URL",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "200px",
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"description": "Link to the page you want to open. Leave blank if you want to make it a group parent.",
|
||||
"fieldname": "url",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "URL",
|
||||
"print_width": "200px",
|
||||
"width": "200px"
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"description": "Select target = \"_blank\" to open in a new page.",
|
||||
"fieldname": "target",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Target",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\ntarget = \"_blank\"",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"description": "Select target = \"_blank\" to open in a new page.",
|
||||
"fieldname": "target",
|
||||
"fieldtype": "Select",
|
||||
"label": "Target",
|
||||
"options": "\ntarget = \"_blank\""
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"default": "1",
|
||||
"description": "For top bar",
|
||||
"fieldname": "right",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Right",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"default": "1",
|
||||
"description": "For top bar",
|
||||
"fieldname": "right",
|
||||
"fieldtype": "Check",
|
||||
"label": "Right"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"description": "If Icon is set, it will be shown instead of Label",
|
||||
"fieldname": "icon",
|
||||
"fieldtype": "Attach Image",
|
||||
"label": "Icon"
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2016-07-11 03:28:09.550365",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Top Bar Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_order": "ASC",
|
||||
"track_seen": 0
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-11 06:12:13.191644",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Top Bar Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC"
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ from jinja2.exceptions import TemplateSyntaxError
|
|||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import get_datetime, now, strip_html
|
||||
from frappe.utils.jinja import render_template, component
|
||||
from frappe.utils.jinja import render_template
|
||||
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
|
||||
from frappe.website.router import resolve_route
|
||||
from frappe.website.utils import (extract_title, find_first_image, get_comment_list,
|
||||
|
|
@ -205,7 +205,8 @@ def get_web_blocks_html(blocks):
|
|||
out = frappe._dict(html='', scripts=[])
|
||||
extracted_scripts = []
|
||||
for block in blocks:
|
||||
rendered_html = component('web_block', web_block=block)
|
||||
rendered_html = frappe.render_template('templates/includes/web_block.html',
|
||||
context={'web_block': block})
|
||||
html, scripts = extract_script_tags(rendered_html)
|
||||
out.html += html
|
||||
if block.web_template not in extracted_scripts:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@
|
|||
"css_class",
|
||||
"column_break_5",
|
||||
"add_container",
|
||||
"add_padding",
|
||||
"add_top_padding",
|
||||
"add_bottom_padding",
|
||||
"add_shade",
|
||||
"hide_block"
|
||||
],
|
||||
|
|
@ -45,12 +46,6 @@
|
|||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "add_padding",
|
||||
"fieldtype": "Check",
|
||||
"label": "Add Padding"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "add_shade",
|
||||
|
|
@ -68,11 +63,23 @@
|
|||
"fieldname": "hide_block",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Block"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "add_top_padding",
|
||||
"fieldtype": "Check",
|
||||
"label": "Add Space on Top"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "add_bottom_padding",
|
||||
"fieldtype": "Check",
|
||||
"label": "Add Space on Bottom"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-29 15:08:25.976179",
|
||||
"modified": "2020-05-11 15:21:54.247652",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Web Page Block",
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ class TestWebTemplate(unittest.TestCase):
|
|||
self.assertEqual(sections[0].find("p").text, "test lorem ipsum")
|
||||
self.assertEqual(len(sections[1].find_all("a")), 3)
|
||||
|
||||
def test_tailwind_styles_in_developer_mode(self):
|
||||
def test_custom_stylesheet(self):
|
||||
self.create_web_page()
|
||||
theme = self.create_tailwind_theme()
|
||||
theme = self.create_website_theme()
|
||||
theme.set_as_default()
|
||||
|
||||
frappe.conf.developer_mode = 1
|
||||
|
|
@ -65,30 +65,9 @@ class TestWebTemplate(unittest.TestCase):
|
|||
soup = BeautifulSoup(html, "html.parser")
|
||||
stylesheet = soup.select_one('link[rel="stylesheet"]')
|
||||
|
||||
self.assertEqual(stylesheet.attrs['href'], '/assets/css/tailwind.css')
|
||||
self.assertEqual(stylesheet.attrs["href"], theme.theme_url)
|
||||
|
||||
frappe.get_doc('Website Theme', 'Standard').set_as_default()
|
||||
|
||||
def test_tailwind_styles_in_production(self):
|
||||
self.create_web_page()
|
||||
theme = self.create_tailwind_theme()
|
||||
theme.set_as_default()
|
||||
|
||||
frappe.conf.developer_mode = 0
|
||||
|
||||
set_request(method="GET", path="test-web-template")
|
||||
response = render()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
html = frappe.safe_decode(response.get_data())
|
||||
|
||||
soup = BeautifulSoup(html, "html.parser")
|
||||
style = soup.select_one("style[data-tailwind]")
|
||||
|
||||
self.assertTrue(style)
|
||||
self.assertTrue('py-20' in style.text)
|
||||
self.assertTrue('text-gray-900' in style.text)
|
||||
|
||||
frappe.get_doc('Website Theme', 'Standard').set_as_default()
|
||||
frappe.get_doc("Website Theme", "Standard").set_as_default()
|
||||
|
||||
def create_web_page(self):
|
||||
if not frappe.db.exists("Web Page", "test-web-template"):
|
||||
|
|
@ -130,13 +109,9 @@ class TestWebTemplate(unittest.TestCase):
|
|||
}
|
||||
).insert()
|
||||
|
||||
def create_tailwind_theme(self):
|
||||
if not frappe.db.exists('Website Theme', 'Tailwind'):
|
||||
theme = frappe.get_doc({
|
||||
'doctype': 'Website Theme',
|
||||
'theme': 'Tailwind',
|
||||
'based_on': 'Tailwind'
|
||||
}).insert()
|
||||
def create_website_theme(self):
|
||||
if not frappe.db.exists("Website Theme", "Custom"):
|
||||
theme = frappe.get_doc({"doctype": "Website Theme", "theme": "Custom"}).insert()
|
||||
else:
|
||||
theme = frappe.get_doc('Website Theme', 'Tailwind')
|
||||
theme = frappe.get_doc("Website Theme", "Custom")
|
||||
return theme
|
||||
|
|
|
|||
|
|
@ -21,9 +21,12 @@
|
|||
"top_bar",
|
||||
"navbar_search",
|
||||
"top_bar_items",
|
||||
"call_to_action",
|
||||
"call_to_action_url",
|
||||
"banner",
|
||||
"banner_html",
|
||||
"footer",
|
||||
"footer_logo",
|
||||
"copyright",
|
||||
"address",
|
||||
"footer_items",
|
||||
|
|
@ -161,20 +164,17 @@
|
|||
"label": "Footer"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.footer_type==='Standard'",
|
||||
"fieldname": "copyright",
|
||||
"fieldtype": "Data",
|
||||
"label": "Copyright"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.footer_type==='Standard'",
|
||||
"description": "Address and other legal information you may want to put in the footer.",
|
||||
"fieldname": "address",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Address"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.footer_type==='Standard'",
|
||||
"fieldname": "footer_items",
|
||||
"fieldtype": "Table",
|
||||
"label": "Footer Items",
|
||||
|
|
@ -182,7 +182,6 @@
|
|||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.footer_type==='Standard'",
|
||||
"fieldname": "hide_footer_signup",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Footer Signup"
|
||||
|
|
@ -330,6 +329,21 @@
|
|||
"fieldname": "enable_view_tracking",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable In App Website Tracking"
|
||||
},
|
||||
{
|
||||
"fieldname": "footer_logo",
|
||||
"fieldtype": "Attach Image",
|
||||
"label": "Footer Logo"
|
||||
},
|
||||
{
|
||||
"fieldname": "call_to_action",
|
||||
"fieldtype": "Data",
|
||||
"label": "Call To Action"
|
||||
},
|
||||
{
|
||||
"fieldname": "call_to_action_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Call To Action URL"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-cog",
|
||||
|
|
@ -337,7 +351,7 @@
|
|||
"issingle": 1,
|
||||
"links": [],
|
||||
"max_attachments": 10,
|
||||
"modified": "2020-04-30 12:37:44.070662",
|
||||
"modified": "2020-05-11 07:14:37.302357",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Website Settings",
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ def get_website_settings():
|
|||
for k in ["banner_html", "brand_html", "copyright", "twitter_share_via",
|
||||
"facebook_share", "google_plus_one", "twitter_share", "linked_in_share",
|
||||
"disable_signup", "hide_footer_signup", "head_html", "title_prefix",
|
||||
"navbar_search", "enable_view_tracking"]:
|
||||
"navbar_search", "enable_view_tracking", "footer_logo", "call_to_action", "call_to_action_url"]:
|
||||
if hasattr(settings, k):
|
||||
context[k] = settings.get(k)
|
||||
|
||||
|
|
@ -179,4 +179,4 @@ def get_items(parentfield):
|
|||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def is_chat_enabled():
|
||||
return bool(frappe.db.get_single_value('Website Settings', 'chat_enable'))
|
||||
return bool(frappe.db.get_single_value('Website Settings', 'chat_enable'))
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"theme",
|
||||
"based_on",
|
||||
"module",
|
||||
"custom",
|
||||
"bootstrap_theme_section",
|
||||
|
|
@ -25,16 +24,10 @@
|
|||
"dark_color",
|
||||
"background_color",
|
||||
"stylesheet_section",
|
||||
"theme_scss",
|
||||
"custom_overrides",
|
||||
"custom_scss",
|
||||
"theme_scss",
|
||||
"theme_url",
|
||||
"tailwind_theme_section",
|
||||
"custom_css",
|
||||
"theme_css",
|
||||
"navbar_section",
|
||||
"navbar",
|
||||
"footer_section",
|
||||
"footer",
|
||||
"custom_js_section",
|
||||
"js"
|
||||
],
|
||||
|
|
@ -86,62 +79,11 @@
|
|||
"label": "JavaScript",
|
||||
"options": "JS"
|
||||
},
|
||||
{
|
||||
"default": "Bootstrap 4",
|
||||
"fieldname": "based_on",
|
||||
"fieldtype": "Select",
|
||||
"label": "Theme Based On",
|
||||
"options": "Bootstrap 4\nTailwind"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.based_on == 'Tailwind'",
|
||||
"fieldname": "navbar_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Navbar"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.based_on=='Tailwind'",
|
||||
"fieldname": "tailwind_theme_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Tailwind Theme"
|
||||
},
|
||||
{
|
||||
"fieldname": "bootstrap_theme_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Theme Configuration"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.based_on == 'Tailwind'",
|
||||
"fieldname": "footer_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Footer"
|
||||
},
|
||||
{
|
||||
"fieldname": "navbar",
|
||||
"fieldtype": "Table",
|
||||
"label": "Navbar",
|
||||
"options": "Web Page Block"
|
||||
},
|
||||
{
|
||||
"fieldname": "footer",
|
||||
"fieldtype": "Table",
|
||||
"label": "Footer",
|
||||
"options": "Web Page Block"
|
||||
},
|
||||
{
|
||||
"fieldname": "custom_css",
|
||||
"fieldtype": "Code",
|
||||
"label": "Custom CSS",
|
||||
"options": "CSS"
|
||||
},
|
||||
{
|
||||
"fieldname": "theme_css",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
"label": "Theme CSS",
|
||||
"options": "CSS",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "google_font",
|
||||
"fieldtype": "Data",
|
||||
|
|
@ -177,7 +119,6 @@
|
|||
"options": "Color"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.based_on == 'Bootstrap 4'",
|
||||
"fieldname": "stylesheet_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Stylesheet"
|
||||
|
|
@ -220,10 +161,16 @@
|
|||
{
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "custom_overrides",
|
||||
"fieldtype": "Code",
|
||||
"label": "Custom Overrides",
|
||||
"options": "SCSS"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-04-25 00:00:23.347879",
|
||||
"modified": "2020-05-11 16:01:04.654990",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Website Theme",
|
||||
|
|
|
|||
|
|
@ -41,13 +41,9 @@ class WebsiteTheme(Document):
|
|||
|
||||
def validate_theme(self):
|
||||
'''Generate theme css if theme_scss has changed'''
|
||||
if self.based_on == 'Bootstrap 4':
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
if doc_before_save is None or get_scss(self) != get_scss(doc_before_save):
|
||||
self.generate_bootstrap_theme()
|
||||
|
||||
if self.based_on == 'Tailwind':
|
||||
self.theme_css = frappe.render_template('frappe/website/doctype/website_theme/custom_theme.css', self.as_dict(), is_path=True)
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
if doc_before_save is None or get_scss(self) != get_scss(doc_before_save):
|
||||
self.generate_bootstrap_theme()
|
||||
|
||||
def export_doc(self):
|
||||
"""Export to standard folder `[module]/website_theme/[name]/[name].json`."""
|
||||
|
|
@ -139,5 +135,5 @@ def generate_theme_files_if_not_exist():
|
|||
frappe.log_error(frappe.get_traceback(), "Theme File Generation Failed")
|
||||
|
||||
def get_scss(doc):
|
||||
return (doc.theme_scss or '') + '\n' + (doc.custom_scss or '')
|
||||
return frappe.render_template('frappe/website/doctype/website_theme/website_theme_template.scss', doc.as_dict())
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
{% if google_font %}
|
||||
@import url('https://fonts.googleapis.com/css?family={{ google_font.replace(' ', '+') }}:{{ font_properties }}&display=swap');
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family={{ google_font.replace(' ', '+') }}:{{ font_properties }}&display=swap');
|
||||
$font-family-sans-serif: "{{ google_font }}", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
|
||||
{% endif -%}
|
||||
|
|
@ -14,6 +13,9 @@ $enable-shadows: {{ button_shadows and "true" or "false" }};
|
|||
$enable-gradients: {{ button_gradients and "true" or "false" }};
|
||||
$enable-rounded: {{ button_rounded_corners and "true" or "false" }};
|
||||
|
||||
// Bootstrap Variable Overrides
|
||||
{{ custom_overrides or '' }}
|
||||
|
||||
@import "frappe/public/scss/website";
|
||||
|
||||
{% if font_size -%}
|
||||
|
|
@ -21,3 +23,6 @@ body {
|
|||
font-size: {{ font_size }};
|
||||
}
|
||||
{%- endif %}
|
||||
|
||||
// Custom Theme
|
||||
{{ custom_scss or '' }}
|
||||
|
|
|
|||
|
|
@ -202,9 +202,6 @@ def build_page(path):
|
|||
if '{next}' in html:
|
||||
html = html.replace('{next}', get_next_link(context.route))
|
||||
|
||||
if '<!-- tailwind-styles -->' in html and not frappe.conf.developer_mode:
|
||||
html = add_processed_tailwind_css(html)
|
||||
|
||||
# html = frappe.get_template(context.base_template_path).render(context)
|
||||
|
||||
if can_cache(context.no_cache):
|
||||
|
|
@ -354,19 +351,3 @@ def raise_if_disabled(path):
|
|||
if path == _path and not r.enabled:
|
||||
raise frappe.PermissionError
|
||||
|
||||
def add_processed_tailwind_css(html):
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
replace_string = '<!-- tailwind-styles -->'
|
||||
command = ['node', 'purgecss.js', 'css/tailwind.css', html]
|
||||
process = Popen(command, cwd=frappe.get_app_path('frappe', '..'), stdout=PIPE, stderr=PIPE)
|
||||
|
||||
stdout, stderr = process.communicate()
|
||||
if stderr:
|
||||
stderr = frappe.safe_decode(stderr)
|
||||
print(stderr)
|
||||
else:
|
||||
css = frappe.safe_decode(stdout)
|
||||
html = html.replace(replace_string, '<style data-tailwind>{0}</style>'.format(css))
|
||||
|
||||
return html
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
<div class="py-16">
|
||||
{%- if brand_image -%}
|
||||
<div class="w-20">
|
||||
<img class="w-auto h-8 sm:h-10" src="{{ brand_image }}" alt="{{ brand_label or 'Brand Logo' }}">
|
||||
</div>
|
||||
{%- endif -%}
|
||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between">
|
||||
<div class="grid items-center grid-cols-2 gap-4 my-4 sm:flex sm:space-x-4">
|
||||
{%- for index in ['1', '2', '3', '4', '5', '6', '7', '8'] -%}
|
||||
|
||||
{%- set label = values['item_' + index + '_label'] -%}
|
||||
{%- set url = values['item_' + index + '_url'] -%}
|
||||
|
||||
{%- if label and url -%}
|
||||
{{ c('navbar_link', label=label, url=url) }}
|
||||
{%- endif -%}
|
||||
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
{%- if content -%}
|
||||
<div class="my-4">
|
||||
{{ content }}
|
||||
</div>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
<div class="flex flex-col items-start justify-between pt-4 text-xs text-gray-700 border-t-2 sm:flex-row">
|
||||
<div>
|
||||
{{ address or '' }}
|
||||
</div>
|
||||
<div class="mt-4 sm:mt-0">
|
||||
{{ copyright or '' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
{
|
||||
"creation": "2020-04-19 15:01:23.344637",
|
||||
"docstatus": 0,
|
||||
"doctype": "Web Template",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "brand_image",
|
||||
"fieldtype": "Attach Image",
|
||||
"label": "Brand Image",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "brand_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Brand Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "address",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Address",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "copyright",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Copyright",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_1_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 1 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_1_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 1 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_2_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 2 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_2_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 2 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_3_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 3 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_3_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 3 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_4_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 4 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_4_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 4 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_5_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 5 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_5_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 5 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "content",
|
||||
"fieldtype": "Markdown Editor",
|
||||
"label": "Content",
|
||||
"reqd": 0
|
||||
}
|
||||
],
|
||||
"idx": 0,
|
||||
"modified": "2020-04-26 15:14:15.892042",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Footer Horizontal",
|
||||
"owner": "Administrator",
|
||||
"standard": 1
|
||||
}
|
||||
|
|
@ -1 +1,5 @@
|
|||
{{ c('image_with_blur', src=url, alt=description, class="w-full") }}
|
||||
{{ frappe.render_template('templates/includes/image_with_blur.html', {
|
||||
"src": url,
|
||||
"alt": description,
|
||||
"class": "full-width-image"
|
||||
}) }}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,23 @@
|
|||
<div>
|
||||
<h1 class="text-3xl font-extrabold leading-tight tracking-tight sm:leading-10 sm:text-4xl xl:leading-none xl:text-5xl">
|
||||
<div class="hero-content">
|
||||
<h1>
|
||||
{{ title }}
|
||||
</h1>
|
||||
{%- if subtitle -%}
|
||||
<p
|
||||
class="max-w-2xl mt-3 text-base text-gray-900 sm:mt-5 sm:text-lg md:mt-5 md:text-xl lg:mx-0">
|
||||
<p class="hero-subtitle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
{%- endif -%}
|
||||
{%- if primary_action or secondary_action -%}
|
||||
<div class="mt-5 sm:mt-8">
|
||||
<div class="mt-4">
|
||||
{%- if primary_action -%}
|
||||
{{ c('button', label=primary_action_label, url=primary_action, variant="primary", size="large") }}
|
||||
<a class="btn btn-lg btn-primary" href="{{ primary_action }}">
|
||||
{{ primary_action_label }}
|
||||
</a>
|
||||
{%- endif -%}
|
||||
{%- if secondary_action -%}
|
||||
{{ c('button', label=secondary_action_label, url=secondary_action, variant="secondary", size="large", class="ml-4") }}
|
||||
<a class="ml-3 btn btn-lg btn-primary-light" href="{{ secondary_action }}">
|
||||
{{ secondary_action_label }}
|
||||
</a>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{%- endif -%}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,33 @@
|
|||
<div class="relative flex">
|
||||
<div class="relative flex items-center flex-shrink-0 w-full md:w-6/12">
|
||||
<div class="hero-with-right-image row no-gutters flex-nowrap">
|
||||
<div class="hero-content col-12 col-md-6">
|
||||
<div>
|
||||
<h1
|
||||
class="text-3xl font-extrabold leading-tight tracking-tight sm:leading-10 sm:text-4xl xl:leading-none xl:text-5xl">
|
||||
<h1>
|
||||
{{ title }}
|
||||
</h1>
|
||||
{%- if subtitle -%}
|
||||
<p
|
||||
class="mt-3 text-base text-gray-900 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0">
|
||||
<p class="hero-subtitle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
{%- endif -%}
|
||||
<div class="mt-5 sm:mt-8">
|
||||
<div class="mt-4">
|
||||
{%- if primary_action -%}
|
||||
{{ c('button', label=primary_action_label, url=primary_action, variant="primary", size="large") }}
|
||||
<a class="btn btn-lg btn-primary" href="{{ primary_action }}">
|
||||
{{ primary_action_label }}
|
||||
</a>
|
||||
{%- endif -%}
|
||||
{%- if secondary_action -%}
|
||||
{{ c('button', label=secondary_action_label, url=secondary_action, variant="secondary", size="large", class="ml-4") }}
|
||||
<a class="ml-3 btn btn-lg btn-primary-light" href="{{ secondary_action }}">
|
||||
{{ secondary_action_label }}
|
||||
</a>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{%- if image -%}
|
||||
{{ c('image_with_blur',
|
||||
class=["hidden md:block max-h-144 object-contain", "w-full md:w-6/12" if contain_image else "md:max-w-md lg:max-w-lg xl:max-w-xl xxl:max-w-2xl"],
|
||||
src=image,
|
||||
alt="")
|
||||
}}
|
||||
{{ frappe.render_template('templates/includes/image_with_blur.html', {
|
||||
"src": image,
|
||||
"alt": "",
|
||||
"class": ["hero-image", "contain-image" if contain_image else ""]
|
||||
}) }}
|
||||
{%- endif -%}
|
||||
</div>
|
||||
|
||||
{%- if not contain_image -%}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => document.body.classList.add('overflow-x-hidden'));
|
||||
</script>
|
||||
{%- endif -%}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
<div class="max-w-2xl from-markdown">
|
||||
{{ frappe.utils.md_to_html(content) }}
|
||||
<div class="section-markdown">
|
||||
<div class="from-markdown">
|
||||
{{ frappe.utils.md_to_html(content) }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
<div class="py-2 bg-white border-b border-gray-200 xxl:py-4">
|
||||
<div class="container relative z-10 flex items-center justify-between">
|
||||
<div class="flex items-end flex-shrink-0 w-20">
|
||||
<a href="/" class="block">
|
||||
<img class="w-auto h-8 sm:h-10" src="{{ brand_image }}" alt="Brand Logo">
|
||||
</a>
|
||||
</div>
|
||||
<details class="z-10 flex items-center sm:hidden hide-summary-arrow">
|
||||
<summary class="block h-6 list-none cursor-pointer focus:outline-none focus:shadow-outline">
|
||||
<button class="pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="feather feather-menu">
|
||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</summary>
|
||||
<nav class="absolute inset-x-0 flex flex-col px-4 py-4 bg-white shadow-md">
|
||||
{%- for index in ['1', '2', '3', '4', '5'] -%}
|
||||
|
||||
{%- set label = values['item_' + index + '_label'] -%}
|
||||
{%- set url = values['item_' + index + '_url'] -%}
|
||||
|
||||
{%- if label and url -%}
|
||||
<div class="py-2">
|
||||
{{ c('navbar_link', label=label, url=url) }}
|
||||
</div>
|
||||
{%- endif -%}
|
||||
|
||||
{%- endfor -%}
|
||||
|
||||
{%- if cta_label and cta_url -%}
|
||||
{{ c('button', label=cta_label, url=cta_url, variant="primary", class="mt-2") }}
|
||||
{%- endif -%}
|
||||
</nav>
|
||||
</details>
|
||||
<nav class="items-center hidden text-sm leading-5 sm:flex space-x-8">
|
||||
{%- for index in ['1', '2', '3', '4', '5'] -%}
|
||||
|
||||
{%- set label = values['item_' + index + '_label'] -%}
|
||||
{%- set url = values['item_' + index + '_url'] -%}
|
||||
|
||||
{%- if label and url -%}
|
||||
{{ c('navbar_link', label=label, url=url) }}
|
||||
{%- endif -%}
|
||||
|
||||
{%- endfor -%}
|
||||
|
||||
{%- if cta_label and cta_url -%}
|
||||
{{ c('button', label=cta_label, url=cta_url, variant="primary") }}
|
||||
{%- endif -%}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
{
|
||||
"creation": "2020-04-19 13:49:33.971237",
|
||||
"docstatus": 0,
|
||||
"doctype": "Web Template",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "brand_image",
|
||||
"fieldtype": "Attach Image",
|
||||
"label": "Brand Image",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "brand_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Brand Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cta_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "CTA Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cta_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "CTA URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_1_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 1 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_1_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 1 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_2_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 2 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_2_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 2 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_3_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 3 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_3_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 3 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_4_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 4 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_4_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 4 URL",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_5_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 5 Label",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "item_5_url",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item 5 URL",
|
||||
"reqd": 0
|
||||
}
|
||||
],
|
||||
"idx": 0,
|
||||
"modified": "2020-04-19 13:51:26.391098",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Navbar with Links on Right",
|
||||
"owner": "Administrator",
|
||||
"standard": 1
|
||||
}
|
||||
|
|
@ -1,47 +1,41 @@
|
|||
{%- macro card(title, content, url) -%}
|
||||
{%- set col_classes = resolve_class({
|
||||
'col-12 col-sm-6 col-lg-3': card_size == 'Small',
|
||||
'col-12 col-sm-6 col-lg-4': card_size == 'Medium',
|
||||
'col-12 col-md-6': card_size == 'Large',
|
||||
}) -%}
|
||||
{%- set card_classes = resolve_class({
|
||||
'p-6': card_size == 'Small',
|
||||
'p-7': card_size == 'Medium',
|
||||
'p-8': card_size == 'Large'
|
||||
'card-sm': card_size == 'Small',
|
||||
'card-md': card_size == 'Medium',
|
||||
'card-lg': card_size == 'Large'
|
||||
}) -%}
|
||||
{%- set title_classes = resolve_class({
|
||||
'text-base font-semibold': card_size == 'Small',
|
||||
'text-lg md:text-xl font-semibold': card_size == 'Medium',
|
||||
'text-xl md:text-2xl font-bold': card_size == 'Large'
|
||||
}) -%}
|
||||
{%- set content_classes = resolve_class({
|
||||
'text-sm': card_size == 'Small',
|
||||
'text-base': card_size == 'Medium',
|
||||
'text-base xxl:text-lg': card_size == 'Large'
|
||||
}) -%}
|
||||
|
||||
<a href="{{ url or '#' }}"
|
||||
class="block bg-white border rounded-xl hover:border-gray-600 {{ card_classes }}">
|
||||
<h3 class="leading-none {{ title_classes }}">{{ title }}</h3>
|
||||
<p class="mt-4 text-gray-900 {{ content_classes }}">{{ content or '' }}</p>
|
||||
</a>
|
||||
<div class="mt-4 {{ col_classes }}">
|
||||
<div class="card {{ card_classes }} h-100">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">{{ title or '' }}</h3>
|
||||
<p class="card-text">{{ content or '' }}</p>
|
||||
</div>
|
||||
<a href="{{ url or '#' }}" class="stretched-link"></a>
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- if title -%}
|
||||
<h2 class="text-xl font-bold sm:text-2xl md:text-3xl">{{ title }}</h2>
|
||||
<h2 class="section-title">{{ title }}</h2>
|
||||
{%- endif -%}
|
||||
{%- if subtitle -%}
|
||||
<p class="mt-2 text-base text-gray-900 sm:text-lg max-x-4xl">{{ subtitle }}</p>
|
||||
<p class="section-description">{{ subtitle }}</p>
|
||||
{%- endif -%}
|
||||
{%- set card_size = card_size or 'Small' -%}
|
||||
{%- set classes = resolve_class({
|
||||
'mt-8': title,
|
||||
'sm:grid-cols-2 lg:grid-cols-4': card_size == 'Small',
|
||||
'sm:grid-cols-2 lg:grid-cols-3': card_size == 'Medium',
|
||||
'sm:grid-cols-2': card_size == 'Large',
|
||||
}) -%}
|
||||
<div class="grid grid-cols-1 gap-4 md:gap-6 xl:gap-8 {{ classes }}">
|
||||
{%- for index in ['1', '2', '3', '4', '5', '6', '7', '8'] -%}
|
||||
{%- set title = values['card_' + index + '_title'] -%}
|
||||
{%- set content = values['card_' + index + '_content'] -%}
|
||||
{%- set url = values['card_' + index + '_url'] -%}
|
||||
{%- if title -%}
|
||||
{{ card(title, content, url) }}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
<div class="{{ resolve_class({'mt-4': title}) }}">
|
||||
<div class="row mt-n4">
|
||||
{%- for index in ['1', '2', '3', '4', '5', '6', '7', '8'] -%}
|
||||
{%- set title = values['card_' + index + '_title'] -%}
|
||||
{%- set content = values['card_' + index + '_content'] -%}
|
||||
{%- set url = values['card_' + index + '_url'] -%}
|
||||
{%- if title -%}
|
||||
{{ card(title, content, url) }}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,19 @@
|
|||
<div class="relative">
|
||||
<div class="px-8 py-12 text-center sm:px-12 md:py-20 bg-primary-100 rounded-xl">
|
||||
<h2 class="max-w-xl mx-auto text-2xl font-extrabold leading-tight md:text-4xl">{{ title }}</h2>
|
||||
<p class="max-w-xl mx-auto mt-2 text-base text-gray-900 md:text-lg">{{ subtitle }}</p>
|
||||
<p class="mt-8">
|
||||
{{ c('button', label=cta_label, url=cta_url, variant="primary", size="large") }}
|
||||
</p>
|
||||
<div class="section-cta-container">
|
||||
<div class="section-cta">
|
||||
<h2 class="title">{{ title }}</h2>
|
||||
<p class="subtitle">{{ subtitle }}</p>
|
||||
<div class="mt-4">
|
||||
<a href="{{ cta_url }}" class="btn btn-lg btn-primary">{{ cta_label }}</a>
|
||||
</div>
|
||||
{%- if cta_description -%}
|
||||
<div class="max-w-xl mx-auto mt-2 text-xs text-gray-900">
|
||||
<div class="description">
|
||||
{{ cta_description }}
|
||||
</div>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{%- if show_confetti -%}
|
||||
<div>
|
||||
<div class="absolute top-0 w-5 h-5 -mt-2 bg-green-300 rounded-full left-1/4"></div>
|
||||
<div class="absolute w-4 h-4 bg-orange-300 rounded-full top-2/3 right-1/6"></div>
|
||||
<div class="absolute bottom-0 w-4 h-4 -mb-2 bg-red-300 rounded-full left-1/6"></div>
|
||||
</div>
|
||||
<div class="confetti confetti-1"></div>
|
||||
<div class="confetti confetti-2"></div>
|
||||
<div class="confetti confetti-3"></div>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
<h2 class="text-xl font-bold sm:text-2xl md:text-3xl">{{ title }}</h2>
|
||||
<p class="max-w-4xl mt-2 text-base text-gray-900 sm:text-lg">{{ subtitle }}</p>
|
||||
|
||||
{{ c('image_with_blur', src=image, alt=image_description, class="w-full mt-8 rounded-xl") }}
|
||||
<h2 class="section-title">{{ title }}</h2>
|
||||
<p class="section-description">{{ subtitle }}</p>
|
||||
|
||||
{{ frappe.render_template('templates/includes/image_with_blur.html', {
|
||||
"src": image,
|
||||
"alt": image_description,
|
||||
"class": "section-image"
|
||||
}) }}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<div class="flex items-start">
|
||||
<div class="w-1/2">
|
||||
<div class="section-with-left-image row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<img class="w-full rounded-xl" src="{{ image }}" alt="{{ title }}" />
|
||||
</div>
|
||||
<div class="w-1/2 py-4 ml-8">
|
||||
<h2 class="text-2xl font-bold">{{ title }}</h2>
|
||||
<p class="text-xl text-gray-800">{{ content }}</p>
|
||||
<div class="py-4 col-12 col-sm-6">
|
||||
<h2>{{ title }}</h2>
|
||||
<p>{{ content }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,39 +1,43 @@
|
|||
<h2 class="text-xl font-bold sm:text-2xl md:text-3xl">{{ title }}</h2>
|
||||
<p class="max-w-4xl mt-2 text-base text-gray-900 sm:text-lg">{{ subtitle }}</p>
|
||||
<h2 class="section-title">{{ title }}</h2>
|
||||
<p class="section-description">{{ subtitle }}</p>
|
||||
|
||||
<div class="mt-8">
|
||||
<div class="tabs">
|
||||
{% set ns = namespace(tabs=[]) %}
|
||||
<div class="mt-5">
|
||||
{% set ns = namespace(tabs=[]) %}
|
||||
|
||||
{%- for index in ['1', '2', '3', '4', '5', '6'] -%}
|
||||
{%- for index in ['1', '2', '3', '4', '5', '6'] -%}
|
||||
|
||||
{%- set buttonid = 'id-' + frappe.utils.generate_hash('TabButton', 12) -%}
|
||||
{%- set panelid = 'id-' + frappe.utils.generate_hash('TabPanel', 12) -%}
|
||||
{%- set buttonid = 'id-' + frappe.utils.generate_hash('TabButton', 12) -%}
|
||||
{%- set panelid = 'id-' + frappe.utils.generate_hash('TabPanel', 12) -%}
|
||||
|
||||
{%- set tab = {
|
||||
'title': values['tab_' + index + '_title'],
|
||||
'content': values['tab_' + index + '_content'],
|
||||
'buttonid': buttonid,
|
||||
'panelid': panelid, }
|
||||
-%}
|
||||
{%- set tab = {
|
||||
'title': values['tab_' + index + '_title'],
|
||||
'content': values['tab_' + index + '_content'],
|
||||
'buttonid': buttonid,
|
||||
'panelid': panelid, }
|
||||
-%}
|
||||
|
||||
{%- if tab.title and tab.content -%}
|
||||
{%- set ns.tabs = ns.tabs + [tab] -%}
|
||||
{%- endif -%}
|
||||
{%- if tab.title and tab.content -%}
|
||||
{%- set ns.tabs = ns.tabs + [tab] -%}
|
||||
{%- endif -%}
|
||||
|
||||
{%- endfor -%}
|
||||
<div class="flex py-2 overflow-x-auto space-x-8" role="tablist" aria-label="{{ title or '' }}">
|
||||
{%- for tab in ns.tabs -%}
|
||||
{%- set first_tab = true if loop.index0 == 0 else false -%}
|
||||
<button class="px-2 py-4 font-medium text-gray-800 border-b-2 border-transparent rounded-t-lg hover:text-blue-400 focus:outline-none focus:bg-blue-50" role="tab" aria-selected="false" aria-controls="{{ tab.panelid }}" id="{{ tab.buttonid }}"
|
||||
tabindex="{{ 0 if first_tab else -1 }}">
|
||||
{{ tab.title }}
|
||||
</button>
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
{%- endfor -%}
|
||||
<ul class="nav nav-tabs flex-nowrap overflow-auto" role="tablist" aria-label="{{ title or '' }}">
|
||||
{%- for tab in ns.tabs -%}
|
||||
{%- set first_tab = true if loop.index0 == 0 else false -%}
|
||||
<div class="mt-4 focus:outline-none focus:shadow-outline" id="{{ tab.panelid }}" role="tabpanel" tabindex="0" aria-labelledby="{{ tab.buttonid }}" {{ 'hidden' if not first_tab else '' }}>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if first_tab else '' }}" id="{{ tab.buttonid }}" data-toggle="tab"
|
||||
href="#{{ tab.panelid }}"
|
||||
role="tab" aria-controls="{{ tab.panelid }}" aria-selected="{{ 'true' if first_tab else 'false' }}">
|
||||
{{ tab.title }}
|
||||
</a>
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
<div class="mt-4 tab-content">
|
||||
{%- for tab in ns.tabs -%}
|
||||
{%- set first_tab = true if loop.index0 == 0 else false -%}
|
||||
<div class="tab-pane fade {{ 'show active' if first_tab else '' }}" id="{{ tab.panelid }}" role="tabpanel"
|
||||
aria-labelledby="{{ tab.buttonid }}">
|
||||
<div class="from-markdown">
|
||||
{{ frappe.utils.md_to_html(tab.content) }}
|
||||
</div>
|
||||
|
|
@ -41,71 +45,3 @@
|
|||
{%- endfor -%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
const tabs = document.querySelectorAll('[role="tab"]');
|
||||
const tabList = document.querySelector('[role="tablist"]');
|
||||
|
||||
// Add a click event handler to each tab
|
||||
tabs.forEach(tab => {
|
||||
tab.addEventListener("click", changeTabs);
|
||||
});
|
||||
|
||||
$(tabs[0]).click();
|
||||
|
||||
// Enable arrow navigation between tabs in the tab list
|
||||
let tabFocus = 0;
|
||||
|
||||
tabList.addEventListener("keydown", e => {
|
||||
// Move right
|
||||
if (e.keyCode === 39 || e.keyCode === 37) {
|
||||
tabs[tabFocus].setAttribute("tabindex", -1);
|
||||
if (e.keyCode === 39) {
|
||||
tabFocus++;
|
||||
// If we're at the end, go to the start
|
||||
if (tabFocus >= tabs.length) {
|
||||
tabFocus = 0;
|
||||
}
|
||||
// Move left
|
||||
} else if (e.keyCode === 37) {
|
||||
tabFocus--;
|
||||
// If we're at the start, move to the end
|
||||
if (tabFocus < 0) {
|
||||
tabFocus = tabs.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
tabs[tabFocus].setAttribute("tabindex", 0);
|
||||
tabs[tabFocus].focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function changeTabs(e) {
|
||||
const target = $(e.target);
|
||||
const parent = target.parent();
|
||||
const grandparent = $(parent.parent());
|
||||
const activeClass = 'border-primary-500 text-primary-600';
|
||||
|
||||
// Remove all current selected tabs
|
||||
parent
|
||||
.find('[aria-selected="true"]')
|
||||
.attr("aria-selected", false)
|
||||
.removeClass(activeClass);
|
||||
|
||||
// Set this tab as selected
|
||||
target.attr('aria-selected', true);
|
||||
target.addClass(activeClass);
|
||||
|
||||
// Hide all tab panels
|
||||
grandparent
|
||||
.find('[role="tabpanel"]')
|
||||
.attr("hidden", true);
|
||||
|
||||
// Show the selected panel
|
||||
grandparent.parent()
|
||||
.find(`#${target.attr("aria-controls")}`)
|
||||
.removeAttr("hidden");
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
{
|
||||
"based_on": "Bootstrap 4",
|
||||
"button_gradients": 0,
|
||||
"button_rounded_corners": 1,
|
||||
"button_shadows": 0,
|
||||
"creation": "2015-02-19 13:37:33.925909",
|
||||
"custom": 0,
|
||||
"custom_css": "",
|
||||
"custom_overrides": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Website Theme",
|
||||
"font_properties": "300,600",
|
||||
"footer": [],
|
||||
"font_properties": "400,500,600,700,800",
|
||||
"idx": 26,
|
||||
"modified": "2020-04-29 12:26:48.399125",
|
||||
"modified": "2020-05-09 16:44:18.508471",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Standard",
|
||||
"navbar": [],
|
||||
"owner": "Administrator",
|
||||
"theme": "Standard",
|
||||
"theme_scss": "$enable-shadows: false;\n$enable-gradients: false;\n$enable-rounded: true;\n\n@import \"frappe/public/scss/website\";\n\n",
|
||||
"theme_scss": "$enable-shadows: false;\n$enable-gradients: false;\n$enable-rounded: true;\n\n// Bootstrap Variable Overrides\n\n\n@import \"frappe/public/scss/website\";\n\n\n\n// Custom Theme\n",
|
||||
"theme_url": "/assets/css/standard_style.css"
|
||||
}
|
||||
|
|
@ -5,7 +5,8 @@
|
|||
"production": "FRAPPE_ENV=production node rollup/build.js",
|
||||
"watch": "node rollup/watch.js",
|
||||
"cypress:open": "cypress open",
|
||||
"snyk-protect": "snyk protect"
|
||||
"snyk-protect": "snyk protect",
|
||||
"prepare": "yarn run snyk-protect"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
@ -18,7 +19,6 @@
|
|||
},
|
||||
"homepage": "https://frappe.io",
|
||||
"dependencies": {
|
||||
"@tailwindcss/ui": "^0.1.3",
|
||||
"ace-builds": "^1.4.8",
|
||||
"air-datepicker": "http://github.com/frappe/air-datepicker",
|
||||
"awesomplete": "^1.1.5",
|
||||
|
|
@ -37,16 +37,14 @@
|
|||
"jsbarcode": "^3.9.0",
|
||||
"moment": "^2.20.1",
|
||||
"moment-timezone": "^0.5.28",
|
||||
"purgecss": "^2.1.0",
|
||||
"quagga": "^0.12.1",
|
||||
"quill": "2.0.0-dev.2",
|
||||
"qz-tray": "^2.0.8",
|
||||
"redis": "^2.8.0",
|
||||
"showdown": "^1.9.1",
|
||||
"snyk": "^1.297.4",
|
||||
"snyk": "^1.316.1",
|
||||
"socket.io": "^2.3.0",
|
||||
"superagent": "^3.8.2",
|
||||
"tailwindcss": "^1.3.3",
|
||||
"touch": "^3.1.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^2.0.0"
|
||||
|
|
@ -58,7 +56,6 @@
|
|||
"cypress-file-upload": "^3.1.0",
|
||||
"less": "^3.11.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"postcss-nested": "^4.2.1",
|
||||
"rollup": "^1.2.2",
|
||||
"rollup-plugin-buble": "^0.19.2",
|
||||
"rollup-plugin-commonjs": "^8.3.0",
|
||||
|
|
|
|||
23
purgecss.js
23
purgecss.js
|
|
@ -1,23 +0,0 @@
|
|||
const path = require('path');
|
||||
const utils = require('./rollup/rollup.utils');
|
||||
const { PurgeCSS } = require('purgecss');
|
||||
|
||||
let css_files = process.argv[2].split(',');
|
||||
let css_file_paths = css_files.map(p => path.resolve(utils.assets_path, p));
|
||||
let html_content = process.argv[3];
|
||||
html_content = html_content.replace(/\\n/g, '\n');
|
||||
|
||||
new PurgeCSS()
|
||||
.purge({
|
||||
content: [
|
||||
{
|
||||
raw: html_content,
|
||||
extension: 'html'
|
||||
}
|
||||
],
|
||||
css: css_file_paths,
|
||||
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
|
||||
})
|
||||
.then(result => {
|
||||
console.log(result[0].css); // eslint-disable-line
|
||||
});
|
||||
|
|
@ -23,10 +23,10 @@ googlemaps==3.1.1
|
|||
gunicorn==19.10.0
|
||||
html2text==2016.9.19
|
||||
html5lib==1.0.1
|
||||
ipython==5.9.0
|
||||
ipython==7.14.0
|
||||
Jinja2==2.11.1
|
||||
ldap3==2.7
|
||||
markdown2==2.3.8
|
||||
markdown2==2.3.9
|
||||
maxminddb-geolite2==2018.703
|
||||
ndg-httpsclient==0.5.1
|
||||
num2words==0.5.5
|
||||
|
|
@ -38,7 +38,6 @@ Pillow==6.2.2
|
|||
premailer==3.6.1
|
||||
psycopg2-binary==2.8.4
|
||||
pyasn1==0.4.8
|
||||
Pygments==2.5.2
|
||||
PyJWT==1.7.1
|
||||
PyMySQL==0.9.3
|
||||
pyOpenSSL==19.1.0
|
||||
|
|
|
|||
|
|
@ -117,9 +117,6 @@ function get_rollup_options_for_css(output_file, input_files) {
|
|||
// less -> css
|
||||
postcss({
|
||||
plugins: [
|
||||
require('tailwindcss'),
|
||||
require('postcss-nested'),
|
||||
require('autoprefixer'),
|
||||
starts_with_css && production ? require('cssnano')({ preset: 'default' }) : null
|
||||
].filter(Boolean),
|
||||
extract: output_path,
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
const defaultTheme = require('tailwindcss/defaultTheme');
|
||||
const colors = require('@tailwindcss/ui/colors');
|
||||
const rgba = require('hex-to-rgba');
|
||||
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['var(--font-family, Inter)', ...defaultTheme.fontFamily.sans]
|
||||
},
|
||||
colors: {
|
||||
primary: {
|
||||
'50': `var(--primary-50, ${colors.blue[50]})`,
|
||||
'100': `var(--primary-100, ${colors.blue[100]})`,
|
||||
'200': `var(--primary-200, ${colors.blue[200]})`,
|
||||
'300': `var(--primary-300, ${colors.blue[300]})`,
|
||||
'400': `var(--primary-400, ${colors.blue[400]})`,
|
||||
'500': `var(--primary-500, ${colors.blue[500]})`,
|
||||
'600': `var(--primary-600, ${colors.blue[600]})`,
|
||||
'700': `var(--primary-700, ${colors.blue[700]})`,
|
||||
'800': `var(--primary-800, ${colors.blue[800]})`,
|
||||
'900': `var(--primary-900, ${colors.blue[900]})`
|
||||
},
|
||||
gray: {
|
||||
'50': `var(--gray-50, ${colors.gray[50]})`,
|
||||
'100': `var(--gray-100, ${colors.gray[100]})`,
|
||||
'200': `var(--gray-200, ${colors.gray[200]})`,
|
||||
'300': `var(--gray-300, ${colors.gray[300]})`,
|
||||
'400': `var(--gray-400, ${colors.gray[400]})`,
|
||||
'500': `var(--gray-500, ${colors.gray[500]})`,
|
||||
'600': `var(--gray-600, ${colors.gray[600]})`,
|
||||
'700': `var(--gray-700, ${colors.gray[700]})`,
|
||||
'800': `var(--gray-800, ${colors.gray[800]})`,
|
||||
'900': `var(--gray-900, ${colors.gray[900]})`
|
||||
},
|
||||
black: '#112B42',
|
||||
code: {
|
||||
green: '#b5f4a5',
|
||||
yellow: '#ffe484',
|
||||
purple: '#d9a9ff',
|
||||
red: '#ff8383',
|
||||
blue: '#93ddfd',
|
||||
white: '#fff'
|
||||
}
|
||||
},
|
||||
borderRadius: {
|
||||
xl: '0.75rem'
|
||||
},
|
||||
maxHeight: {
|
||||
'144': '36rem'
|
||||
},
|
||||
boxShadow: theme => ({
|
||||
'outline-primary': `0 0 0 3px ${rgba(theme('colors.blue.300'), 0.45)}`
|
||||
}),
|
||||
container: {
|
||||
center: true,
|
||||
padding: {
|
||||
default: '1.25rem',
|
||||
sm: '2rem',
|
||||
lg: '3rem',
|
||||
xl: '12rem',
|
||||
xxl: '11rem'
|
||||
}
|
||||
},
|
||||
screens: {
|
||||
xxl: '1440px'
|
||||
}
|
||||
}
|
||||
},
|
||||
variants: {},
|
||||
plugins: [require('@tailwindcss/ui')]
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue