Merge remote-tracking branch 'upstream/develop' into fix/float-input-formatting

This commit is contained in:
David Arnold 2023-11-13 10:00:16 +01:00
commit 3559c8bc18
No known key found for this signature in database
GPG key ID: AB15A6AF1101390D
132 changed files with 2972 additions and 2065 deletions

View file

@ -35,7 +35,7 @@ repos:
rev: v2.7.1
hooks:
- id: prettier
types_or: [javascript]
types_or: [javascript, vue, scss]
# Ignore any files that might contain jinja / bundles
exclude: |
(?x)^(
@ -44,7 +44,8 @@ repos:
.*boilerplate.*|
frappe/www/website_script.js|
frappe/templates/includes/.*|
frappe/public/js/lib/.*
frappe/public/js/lib/.*|
frappe/website/doctype/website_theme/website_theme_template.scss
)$

View file

@ -43,7 +43,8 @@ context("Form Builder", () => {
// add new section
cy.get(first_section).click(15, 10);
cy.get(first_section).find(".section-actions button:first").click();
cy.get(first_section).find(".dropdown-btn:first").click();
cy.get(".dropdown-options:visible .dropdown-item:first").click();
// save
cy.click_doc_primary_button("Save");
@ -184,12 +185,14 @@ context("Form Builder", () => {
// add new section
cy.get(first_section).click(15, 10);
cy.get(first_section).find(".section-actions button:first").click();
cy.get(first_section).find(".dropdown-btn:first").click();
cy.get(".dropdown-options:visible .dropdown-item:first").click();
cy.get(".tab-content.active .form-section-container").should("have.length", 2);
// add new column
cy.get(first_section).find(".column:first").click(15, 10);
cy.get(first_section).find(".column:first .column-actions button:first").click();
cy.get(first_section).click(15, 10);
cy.get(first_section).find(".dropdown-btn:first").click();
cy.get(".dropdown-options:visible .dropdown-item:last").click();
cy.get(first_section).find(".column").should("have.length", 2);
});
@ -197,13 +200,15 @@ context("Form Builder", () => {
let first_section = ".tab-content.active .form-section-container:first";
// remove column
cy.get(first_section).find(".column:first").click(15, 10);
cy.get(first_section).find(".column:first .column-actions button:last").click();
cy.get(first_section).click(15, 10);
cy.get(first_section).find(".dropdown-btn:first").click();
cy.get(".dropdown-options:visible .dropdown-item:last").click();
cy.get(first_section).find(".column").should("have.length", 1);
// remove section
cy.get(first_section).click(15, 10);
cy.get(first_section).find(".section-actions button:last").click();
cy.get(first_section).find(".dropdown-btn:first").click();
cy.get(".dropdown-options:visible .dropdown-item").eq(1).click();
cy.get(".tab-content.active .form-section-container").should("have.length", 1);
// remove tab

View file

@ -416,7 +416,7 @@
"width": "50px"
},
{
"description": "Number of columns for a field in a List View or a Grid (Total Columns should be less than 11)",
"description": "Number of columns for a field in a grid (total columns should be less than 11)",
"fieldname": "columns",
"fieldtype": "Int",
"label": "Columns"

View file

@ -376,7 +376,7 @@ def relink_files(doc, fieldname, temp_doc_name):
"attached_to_field": fieldname,
"creation": (
"between",
[now_datetime() - add_to_date(date=now_datetime(), minutes=-60), now_datetime()],
[add_to_date(date=now_datetime(), minutes=-60), now_datetime()],
),
},
)

View file

@ -87,7 +87,9 @@ class RQJob(Document):
matched_job_ids = RQJob.get_matching_job_ids(args)[start : start + page_length]
conn = get_redis_conn()
jobs = [serialize_job(job) for job in Job.fetch_many(job_ids=matched_job_ids, connection=conn)]
jobs = [
serialize_job(job) for job in Job.fetch_many(job_ids=matched_job_ids, connection=conn) if job
]
return sorted(jobs, key=lambda j: j.modified, reverse=order_desc)

View file

@ -30,10 +30,10 @@
"links",
"document_states_section",
"states",
"form_tab",
"form_builder",
"fields_section_break",
"fields",
"form_tab",
"form_builder",
"settings_tab",
"form_settings_section",
"image_field",
@ -180,7 +180,6 @@
"depends_on": "doc_type",
"fieldname": "fields_section_break",
"fieldtype": "Section Break",
"hidden": 1,
"label": "Fields"
},
{
@ -394,7 +393,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-10-31 02:04:25.955931",
"modified": "2023-11-07 19:25:32.656641",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form",

View file

@ -160,11 +160,16 @@ class PostgresDatabase(PostgresExceptionUtil, Database):
return LazyDecode(self._cursor.query)
def get_connection(self):
conn = psycopg2.connect(
"host='{}' dbname='{}' user='{}' password='{}' port={}".format(
self.host, self.user, self.user, self.password, self.port
)
)
conn_settings = {
"user": self.user,
"dbname": self.user,
"host": self.host,
"password": self.password,
}
if self.port:
conn_settings["port"] = self.port
conn = psycopg2.connect(**conn_settings)
conn.set_isolation_level(ISOLATION_LEVEL_REPEATABLE_READ)
return conn

View file

@ -4,7 +4,7 @@
import json
import frappe
from frappe.integrations.utils import json_handler
from frappe.integrations.utils import get_json, json_handler
from frappe.model.document import Document
@ -45,7 +45,7 @@ class IntegrationRequest(Document):
data = json.loads(self.data)
data.update(params)
self.data = json.dumps(data)
self.data = get_json(data)
self.status = status
self.save(ignore_permissions=True)
frappe.db.commit()

View file

@ -1,164 +1,167 @@
// TODO instead of making copy of inter.css find a way to import it.
// workaround for css import as it fails for custom website_theme_template
@font-face {
font-family: 'Inter V';
font-family: "Inter V";
font-weight: 100 900;
font-display: swap;
font-style: normal;
src: url('/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19') format('woff2-variations'),
url('/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19') format('woff2');
src: url('/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19') format('woff2') tech('variations');
}
@font-face {
font-family: 'Inter V';
src: url("/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19") format("woff2-variations"),
url("/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19") format("woff2");
src: url("/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19") format("woff2")
tech("variations");
}
@font-face {
font-family: "Inter V";
font-weight: 100 900;
font-display: swap;
font-style: italic;
src: url('/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19') format('woff2-variations'),
url('/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19') format('woff2');
src: url('/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19') format('woff2') tech('variations');
}
src: url("/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19")
format("woff2-variations"),
url("/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19") format("woff2");
src: url("/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19") format("woff2")
tech("variations");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 100;
src: url("/assets/frappe/css/fonts/inter/inter_thinitalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_thinitalic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_thinitalic.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: normal;
font-style: normal;
font-weight: 200;
src: url("/assets/frappe/css/fonts/inter/inter_extralight.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_extralight.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_extralight.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 200;
src: url("/assets/frappe/css/fonts/inter/inter_extralightitalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_extralightitalic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_extralightitalic.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: normal;
font-style: normal;
font-weight: 300;
src: url("/assets/frappe/css/fonts/inter/inter_light.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_light.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_light.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 300;
src: url("/assets/frappe/css/fonts/inter/inter_lightitalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_lightitalic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_lightitalic.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: normal;
font-style: normal;
font-weight: 400;
src: url("/assets/frappe/css/fonts/inter/inter_regular.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_regular.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_regular.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 400;
src: url("/assets/frappe/css/fonts/inter/inter_italic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_italic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_italic.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: normal;
font-style: normal;
font-weight: 500;
src: url("/assets/frappe/css/fonts/inter/inter_medium.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_medium.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_medium.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 500;
src: url("/assets/frappe/css/fonts/inter/inter_mediumitalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_mediumitalic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_mediumitalic.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: normal;
font-style: normal;
font-weight: 600;
src: url("/assets/frappe/css/fonts/inter/inter_semibold.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_semibold.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_semibold.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 600;
src: url("/assets/frappe/css/fonts/inter/inter_semibolditalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_semibolditalic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_semibolditalic.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: normal;
font-style: normal;
font-weight: 700;
src: url("/assets/frappe/css/fonts/inter/inter_bold.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_bold.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_bold.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 700;
src: url("/assets/frappe/css/fonts/inter/inter_bolditalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_bolditalic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_bolditalic.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: normal;
font-style: normal;
font-weight: 800;
src: url("/assets/frappe/css/fonts/inter/inter_extrabold.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_extrabold.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_extrabold.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 800;
src: url("/assets/frappe/css/fonts/inter/inter_extrabolditalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_extrabolditalic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_extrabolditalic.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: normal;
font-style: normal;
font-weight: 900;
src: url("/assets/frappe/css/fonts/inter/inter_black.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_black.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_black.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-family: "Inter";
font-display: swap;
font-style: italic;
font-style: italic;
font-weight: 900;
src: url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff") format("woff");
url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff") format("woff");
}

View file

@ -1,220 +1,548 @@
$octicons-font-path: "." !default;
$octicons-version: "396334ee3da78f4302d25c758ae3e3ce5dc3c97d";
$octicons-version: "396334ee3da78f4302d25c758ae3e3ce5dc3c97d";
@font-face {
font-family: 'octicons';
src: url('#{$octicons-font-path}/octicons.eot?#iefix&v=#{$octicons-version}') format('embedded-opentype'),
url('#{$octicons-font-path}/octicons.woff?v=#{$octicons-version}') format('woff'),
url('#{$octicons-font-path}/octicons.ttf?v=#{$octicons-version}') format('truetype'),
url('#{$octicons-font-path}/octicons.svg?v=#{$octicons-version}#octicons') format('svg');
font-weight: normal;
font-style: normal;
font-family: "octicons";
src: url("#{$octicons-font-path}/octicons.eot?#iefix&v=#{$octicons-version}")
format("embedded-opentype"),
url("#{$octicons-font-path}/octicons.woff?v=#{$octicons-version}") format("woff"),
url("#{$octicons-font-path}/octicons.ttf?v=#{$octicons-version}") format("truetype"),
url("#{$octicons-font-path}/octicons.svg?v=#{$octicons-version}#octicons") format("svg");
font-weight: normal;
font-style: normal;
}
// .octicon is optimized for 16px.
// .mega-octicon is optimized for 32px but can be used larger.
.octicon, .mega-octicon {
font: normal normal normal 16px/1 octicons;
display: inline-block;
text-decoration: none;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.octicon,
.mega-octicon {
font: normal normal normal 16px/1 octicons;
display: inline-block;
text-decoration: none;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mega-octicon {
font-size: 32px;
}
.mega-octicon { font-size: 32px; }
.octicon-alert:before { content: '\f02d'} /*  */
.octicon-arrow-down:before { content: '\f03f'} /*  */
.octicon-arrow-left:before { content: '\f040'} /*  */
.octicon-arrow-right:before { content: '\f03e'} /*  */
.octicon-arrow-small-down:before { content: '\f0a0'} /*  */
.octicon-arrow-small-left:before { content: '\f0a1'} /*  */
.octicon-arrow-small-right:before { content: '\f071'} /*  */
.octicon-arrow-small-up:before { content: '\f09f'} /*  */
.octicon-arrow-up:before { content: '\f03d'} /*  */
.octicon-alert:before {
content: "\f02d";
} /*  */
.octicon-arrow-down:before {
content: "\f03f";
} /*  */
.octicon-arrow-left:before {
content: "\f040";
} /*  */
.octicon-arrow-right:before {
content: "\f03e";
} /*  */
.octicon-arrow-small-down:before {
content: "\f0a0";
} /*  */
.octicon-arrow-small-left:before {
content: "\f0a1";
} /*  */
.octicon-arrow-small-right:before {
content: "\f071";
} /*  */
.octicon-arrow-small-up:before {
content: "\f09f";
} /*  */
.octicon-arrow-up:before {
content: "\f03d";
} /*  */
.octicon-microscope:before,
.octicon-beaker:before { content: '\f0dd'} /*  */
.octicon-bell:before { content: '\f0de'} /*  */
.octicon-book:before { content: '\f007'} /*  */
.octicon-bookmark:before { content: '\f07b'} /*  */
.octicon-briefcase:before { content: '\f0d3'} /*  */
.octicon-broadcast:before { content: '\f048'} /*  */
.octicon-browser:before { content: '\f0c5'} /*  */
.octicon-bug:before { content: '\f091'} /*  */
.octicon-calendar:before { content: '\f068'} /*  */
.octicon-check:before { content: '\f03a'} /*  */
.octicon-checklist:before { content: '\f076'} /*  */
.octicon-chevron-down:before { content: '\f0a3'} /*  */
.octicon-chevron-left:before { content: '\f0a4'} /*  */
.octicon-chevron-right:before { content: '\f078'} /*  */
.octicon-chevron-up:before { content: '\f0a2'} /*  */
.octicon-circle-slash:before { content: '\f084'} /*  */
.octicon-circuit-board:before { content: '\f0d6'} /*  */
.octicon-clippy:before { content: '\f035'} /*  */
.octicon-clock:before { content: '\f046'} /*  */
.octicon-cloud-download:before { content: '\f00b'} /*  */
.octicon-cloud-upload:before { content: '\f00c'} /*  */
.octicon-code:before { content: '\f05f'} /*  */
.octicon-color-mode:before { content: '\f065'} /*  */
.octicon-beaker:before {
content: "\f0dd";
} /*  */
.octicon-bell:before {
content: "\f0de";
} /*  */
.octicon-book:before {
content: "\f007";
} /*  */
.octicon-bookmark:before {
content: "\f07b";
} /*  */
.octicon-briefcase:before {
content: "\f0d3";
} /*  */
.octicon-broadcast:before {
content: "\f048";
} /*  */
.octicon-browser:before {
content: "\f0c5";
} /*  */
.octicon-bug:before {
content: "\f091";
} /*  */
.octicon-calendar:before {
content: "\f068";
} /*  */
.octicon-check:before {
content: "\f03a";
} /*  */
.octicon-checklist:before {
content: "\f076";
} /*  */
.octicon-chevron-down:before {
content: "\f0a3";
} /*  */
.octicon-chevron-left:before {
content: "\f0a4";
} /*  */
.octicon-chevron-right:before {
content: "\f078";
} /*  */
.octicon-chevron-up:before {
content: "\f0a2";
} /*  */
.octicon-circle-slash:before {
content: "\f084";
} /*  */
.octicon-circuit-board:before {
content: "\f0d6";
} /*  */
.octicon-clippy:before {
content: "\f035";
} /*  */
.octicon-clock:before {
content: "\f046";
} /*  */
.octicon-cloud-download:before {
content: "\f00b";
} /*  */
.octicon-cloud-upload:before {
content: "\f00c";
} /*  */
.octicon-code:before {
content: "\f05f";
} /*  */
.octicon-color-mode:before {
content: "\f065";
} /*  */
.octicon-comment-add:before,
.octicon-comment:before { content: '\f02b'} /*  */
.octicon-comment-discussion:before { content: '\f04f'} /*  */
.octicon-credit-card:before { content: '\f045'} /*  */
.octicon-dash:before { content: '\f0ca'} /*  */
.octicon-dashboard:before { content: '\f07d'} /*  */
.octicon-database:before { content: '\f096'} /*  */
.octicon-comment:before {
content: "\f02b";
} /*  */
.octicon-comment-discussion:before {
content: "\f04f";
} /*  */
.octicon-credit-card:before {
content: "\f045";
} /*  */
.octicon-dash:before {
content: "\f0ca";
} /*  */
.octicon-dashboard:before {
content: "\f07d";
} /*  */
.octicon-database:before {
content: "\f096";
} /*  */
.octicon-clone:before,
.octicon-desktop-download:before { content: '\f0dc'} /*  */
.octicon-device-camera:before { content: '\f056'} /*  */
.octicon-device-camera-video:before { content: '\f057'} /*  */
.octicon-device-desktop:before { content: '\f27c'} /*  */
.octicon-device-mobile:before { content: '\f038'} /*  */
.octicon-diff:before { content: '\f04d'} /*  */
.octicon-diff-added:before { content: '\f06b'} /*  */
.octicon-diff-ignored:before { content: '\f099'} /*  */
.octicon-diff-modified:before { content: '\f06d'} /*  */
.octicon-diff-removed:before { content: '\f06c'} /*  */
.octicon-diff-renamed:before { content: '\f06e'} /*  */
.octicon-ellipsis:before { content: '\f09a'} /*  */
.octicon-desktop-download:before {
content: "\f0dc";
} /*  */
.octicon-device-camera:before {
content: "\f056";
} /*  */
.octicon-device-camera-video:before {
content: "\f057";
} /*  */
.octicon-device-desktop:before {
content: "\f27c";
} /*  */
.octicon-device-mobile:before {
content: "\f038";
} /*  */
.octicon-diff:before {
content: "\f04d";
} /*  */
.octicon-diff-added:before {
content: "\f06b";
} /*  */
.octicon-diff-ignored:before {
content: "\f099";
} /*  */
.octicon-diff-modified:before {
content: "\f06d";
} /*  */
.octicon-diff-removed:before {
content: "\f06c";
} /*  */
.octicon-diff-renamed:before {
content: "\f06e";
} /*  */
.octicon-ellipsis:before {
content: "\f09a";
} /*  */
.octicon-eye-unwatch:before,
.octicon-eye-watch:before,
.octicon-eye:before { content: '\f04e'} /*  */
.octicon-file-binary:before { content: '\f094'} /*  */
.octicon-file-code:before { content: '\f010'} /*  */
.octicon-file-directory:before { content: '\f016'} /*  */
.octicon-file-media:before { content: '\f012'} /*  */
.octicon-file-pdf:before { content: '\f014'} /*  */
.octicon-file-submodule:before { content: '\f017'} /*  */
.octicon-file-symlink-directory:before { content: '\f0b1'} /*  */
.octicon-file-symlink-file:before { content: '\f0b0'} /*  */
.octicon-file-text:before { content: '\f011'} /*  */
.octicon-file-zip:before { content: '\f013'} /*  */
.octicon-flame:before { content: '\f0d2'} /*  */
.octicon-fold:before { content: '\f0cc'} /*  */
.octicon-gear:before { content: '\f02f'} /*  */
.octicon-gift:before { content: '\f042'} /*  */
.octicon-gist:before { content: '\f00e'} /*  */
.octicon-gist-secret:before { content: '\f08c'} /*  */
.octicon-eye:before {
content: "\f04e";
} /*  */
.octicon-file-binary:before {
content: "\f094";
} /*  */
.octicon-file-code:before {
content: "\f010";
} /*  */
.octicon-file-directory:before {
content: "\f016";
} /*  */
.octicon-file-media:before {
content: "\f012";
} /*  */
.octicon-file-pdf:before {
content: "\f014";
} /*  */
.octicon-file-submodule:before {
content: "\f017";
} /*  */
.octicon-file-symlink-directory:before {
content: "\f0b1";
} /*  */
.octicon-file-symlink-file:before {
content: "\f0b0";
} /*  */
.octicon-file-text:before {
content: "\f011";
} /*  */
.octicon-file-zip:before {
content: "\f013";
} /*  */
.octicon-flame:before {
content: "\f0d2";
} /*  */
.octicon-fold:before {
content: "\f0cc";
} /*  */
.octicon-gear:before {
content: "\f02f";
} /*  */
.octicon-gift:before {
content: "\f042";
} /*  */
.octicon-gist:before {
content: "\f00e";
} /*  */
.octicon-gist-secret:before {
content: "\f08c";
} /*  */
.octicon-git-branch-create:before,
.octicon-git-branch-delete:before,
.octicon-git-branch:before { content: '\f020'} /*  */
.octicon-git-commit:before { content: '\f01f'} /*  */
.octicon-git-compare:before { content: '\f0ac'} /*  */
.octicon-git-merge:before { content: '\f023'} /*  */
.octicon-git-branch:before {
content: "\f020";
} /*  */
.octicon-git-commit:before {
content: "\f01f";
} /*  */
.octicon-git-compare:before {
content: "\f0ac";
} /*  */
.octicon-git-merge:before {
content: "\f023";
} /*  */
.octicon-git-pull-request-abandoned:before,
.octicon-git-pull-request:before { content: '\f009'} /*  */
.octicon-globe:before { content: '\f0b6'} /*  */
.octicon-graph:before { content: '\f043'} /*  */
.octicon-heart:before { content: '\2665'} /* ♥ */
.octicon-history:before { content: '\f07e'} /*  */
.octicon-home:before { content: '\f08d'} /*  */
.octicon-horizontal-rule:before { content: '\f070'} /*  */
.octicon-hubot:before { content: '\f09d'} /*  */
.octicon-inbox:before { content: '\f0cf'} /*  */
.octicon-info:before { content: '\f059'} /*  */
.octicon-issue-closed:before { content: '\f028'} /*  */
.octicon-issue-opened:before { content: '\f026'} /*  */
.octicon-issue-reopened:before { content: '\f027'} /*  */
.octicon-jersey:before { content: '\f019'} /*  */
.octicon-key:before { content: '\f049'} /*  */
.octicon-keyboard:before { content: '\f00d'} /*  */
.octicon-law:before { content: '\f0d8'} /*  */
.octicon-light-bulb:before { content: '\f000'} /*  */
.octicon-link:before { content: '\f05c'} /*  */
.octicon-link-external:before { content: '\f07f'} /*  */
.octicon-list-ordered:before { content: '\f062'} /*  */
.octicon-list-unordered:before { content: '\f061'} /*  */
.octicon-location:before { content: '\f060'} /*  */
.octicon-git-pull-request:before {
content: "\f009";
} /*  */
.octicon-globe:before {
content: "\f0b6";
} /*  */
.octicon-graph:before {
content: "\f043";
} /*  */
.octicon-heart:before {
content: "\2665";
} /* ♥ */
.octicon-history:before {
content: "\f07e";
} /*  */
.octicon-home:before {
content: "\f08d";
} /*  */
.octicon-horizontal-rule:before {
content: "\f070";
} /*  */
.octicon-hubot:before {
content: "\f09d";
} /*  */
.octicon-inbox:before {
content: "\f0cf";
} /*  */
.octicon-info:before {
content: "\f059";
} /*  */
.octicon-issue-closed:before {
content: "\f028";
} /*  */
.octicon-issue-opened:before {
content: "\f026";
} /*  */
.octicon-issue-reopened:before {
content: "\f027";
} /*  */
.octicon-jersey:before {
content: "\f019";
} /*  */
.octicon-key:before {
content: "\f049";
} /*  */
.octicon-keyboard:before {
content: "\f00d";
} /*  */
.octicon-law:before {
content: "\f0d8";
} /*  */
.octicon-light-bulb:before {
content: "\f000";
} /*  */
.octicon-link:before {
content: "\f05c";
} /*  */
.octicon-link-external:before {
content: "\f07f";
} /*  */
.octicon-list-ordered:before {
content: "\f062";
} /*  */
.octicon-list-unordered:before {
content: "\f061";
} /*  */
.octicon-location:before {
content: "\f060";
} /*  */
.octicon-gist-private:before,
.octicon-mirror-private:before,
.octicon-git-fork-private:before,
.octicon-lock:before { content: '\f06a'} /*  */
.octicon-logo-github:before { content: '\f092'} /*  */
.octicon-mail:before { content: '\f03b'} /*  */
.octicon-mail-read:before { content: '\f03c'} /*  */
.octicon-mail-reply:before { content: '\f051'} /*  */
.octicon-mark-github:before { content: '\f00a'} /*  */
.octicon-markdown:before { content: '\f0c9'} /*  */
.octicon-megaphone:before { content: '\f077'} /*  */
.octicon-mention:before { content: '\f0be'} /*  */
.octicon-milestone:before { content: '\f075'} /*  */
.octicon-lock:before {
content: "\f06a";
} /*  */
.octicon-logo-github:before {
content: "\f092";
} /*  */
.octicon-mail:before {
content: "\f03b";
} /*  */
.octicon-mail-read:before {
content: "\f03c";
} /*  */
.octicon-mail-reply:before {
content: "\f051";
} /*  */
.octicon-mark-github:before {
content: "\f00a";
} /*  */
.octicon-markdown:before {
content: "\f0c9";
} /*  */
.octicon-megaphone:before {
content: "\f077";
} /*  */
.octicon-mention:before {
content: "\f0be";
} /*  */
.octicon-milestone:before {
content: "\f075";
} /*  */
.octicon-mirror-public:before,
.octicon-mirror:before { content: '\f024'} /*  */
.octicon-mortar-board:before { content: '\f0d7'} /*  */
.octicon-mute:before { content: '\f080'} /*  */
.octicon-no-newline:before { content: '\f09c'} /*  */
.octicon-octoface:before { content: '\f008'} /*  */
.octicon-organization:before { content: '\f037'} /*  */
.octicon-package:before { content: '\f0c4'} /*  */
.octicon-paintcan:before { content: '\f0d1'} /*  */
.octicon-pencil:before { content: '\f058'} /*  */
.octicon-mirror:before {
content: "\f024";
} /*  */
.octicon-mortar-board:before {
content: "\f0d7";
} /*  */
.octicon-mute:before {
content: "\f080";
} /*  */
.octicon-no-newline:before {
content: "\f09c";
} /*  */
.octicon-octoface:before {
content: "\f008";
} /*  */
.octicon-organization:before {
content: "\f037";
} /*  */
.octicon-package:before {
content: "\f0c4";
} /*  */
.octicon-paintcan:before {
content: "\f0d1";
} /*  */
.octicon-pencil:before {
content: "\f058";
} /*  */
.octicon-person-add:before,
.octicon-person-follow:before,
.octicon-person:before { content: '\f018'} /*  */
.octicon-pin:before { content: '\f041'} /*  */
.octicon-plug:before { content: '\f0d4'} /*  */
.octicon-person:before {
content: "\f018";
} /*  */
.octicon-pin:before {
content: "\f041";
} /*  */
.octicon-plug:before {
content: "\f0d4";
} /*  */
.octicon-repo-create:before,
.octicon-gist-new:before,
.octicon-file-directory-create:before,
.octicon-file-add:before,
.octicon-plus:before { content: '\f05d'} /*  */
.octicon-primitive-dot:before { content: '\f052'} /*  */
.octicon-primitive-square:before { content: '\f053'} /*  */
.octicon-pulse:before { content: '\f085'} /*  */
.octicon-question:before { content: '\f02c'} /*  */
.octicon-quote:before { content: '\f063'} /*  */
.octicon-radio-tower:before { content: '\f030'} /*  */
.octicon-plus:before {
content: "\f05d";
} /*  */
.octicon-primitive-dot:before {
content: "\f052";
} /*  */
.octicon-primitive-square:before {
content: "\f053";
} /*  */
.octicon-pulse:before {
content: "\f085";
} /*  */
.octicon-question:before {
content: "\f02c";
} /*  */
.octicon-quote:before {
content: "\f063";
} /*  */
.octicon-radio-tower:before {
content: "\f030";
} /*  */
.octicon-repo-delete:before,
.octicon-repo:before { content: '\f001'} /*  */
.octicon-repo-clone:before { content: '\f04c'} /*  */
.octicon-repo-force-push:before { content: '\f04a'} /*  */
.octicon-repo:before {
content: "\f001";
} /*  */
.octicon-repo-clone:before {
content: "\f04c";
} /*  */
.octicon-repo-force-push:before {
content: "\f04a";
} /*  */
.octicon-gist-fork:before,
.octicon-repo-forked:before { content: '\f002'} /*  */
.octicon-repo-pull:before { content: '\f006'} /*  */
.octicon-repo-push:before { content: '\f005'} /*  */
.octicon-rocket:before { content: '\f033'} /*  */
.octicon-rss:before { content: '\f034'} /*  */
.octicon-ruby:before { content: '\f047'} /*  */
.octicon-screen-full:before { content: '\f066'} /*  */
.octicon-screen-normal:before { content: '\f067'} /*  */
.octicon-repo-forked:before {
content: "\f002";
} /*  */
.octicon-repo-pull:before {
content: "\f006";
} /*  */
.octicon-repo-push:before {
content: "\f005";
} /*  */
.octicon-rocket:before {
content: "\f033";
} /*  */
.octicon-rss:before {
content: "\f034";
} /*  */
.octicon-ruby:before {
content: "\f047";
} /*  */
.octicon-screen-full:before {
content: "\f066";
} /*  */
.octicon-screen-normal:before {
content: "\f067";
} /*  */
.octicon-search-save:before,
.octicon-search:before { content: '\f02e'} /*  */
.octicon-server:before { content: '\f097'} /*  */
.octicon-settings:before { content: '\f07c'} /*  */
.octicon-shield:before { content: '\f0e1'} /*  */
.octicon-search:before {
content: "\f02e";
} /*  */
.octicon-server:before {
content: "\f097";
} /*  */
.octicon-settings:before {
content: "\f07c";
} /*  */
.octicon-shield:before {
content: "\f0e1";
} /*  */
.octicon-log-in:before,
.octicon-sign-in:before { content: '\f036'} /*  */
.octicon-sign-in:before {
content: "\f036";
} /*  */
.octicon-log-out:before,
.octicon-sign-out:before { content: '\f032'} /*  */
.octicon-squirrel:before { content: '\f0b2'} /*  */
.octicon-sign-out:before {
content: "\f032";
} /*  */
.octicon-squirrel:before {
content: "\f0b2";
} /*  */
.octicon-star-add:before,
.octicon-star-delete:before,
.octicon-star:before { content: '\f02a'} /*  */
.octicon-stop:before { content: '\f08f'} /*  */
.octicon-star:before {
content: "\f02a";
} /*  */
.octicon-stop:before {
content: "\f08f";
} /*  */
.octicon-repo-sync:before,
.octicon-sync:before { content: '\f087'} /*  */
.octicon-sync:before {
content: "\f087";
} /*  */
.octicon-tag-remove:before,
.octicon-tag-add:before,
.octicon-tag:before { content: '\f015'} /*  */
.octicon-telescope:before { content: '\f088'} /*  */
.octicon-terminal:before { content: '\f0c8'} /*  */
.octicon-three-bars:before { content: '\f05e'} /*  */
.octicon-thumbsdown:before { content: '\f0db'} /*  */
.octicon-thumbsup:before { content: '\f0da'} /*  */
.octicon-tools:before { content: '\f031'} /*  */
.octicon-trashcan:before { content: '\f0d0'} /*  */
.octicon-triangle-down:before { content: '\f05b'} /*  */
.octicon-triangle-left:before { content: '\f044'} /*  */
.octicon-triangle-right:before { content: '\f05a'} /*  */
.octicon-triangle-up:before { content: '\f0aa'} /*  */
.octicon-unfold:before { content: '\f039'} /*  */
.octicon-unmute:before { content: '\f0ba'} /*  */
.octicon-versions:before { content: '\f064'} /*  */
.octicon-watch:before { content: '\f0e0'} /*  */
.octicon-tag:before {
content: "\f015";
} /*  */
.octicon-telescope:before {
content: "\f088";
} /*  */
.octicon-terminal:before {
content: "\f0c8";
} /*  */
.octicon-three-bars:before {
content: "\f05e";
} /*  */
.octicon-thumbsdown:before {
content: "\f0db";
} /*  */
.octicon-thumbsup:before {
content: "\f0da";
} /*  */
.octicon-tools:before {
content: "\f031";
} /*  */
.octicon-trashcan:before {
content: "\f0d0";
} /*  */
.octicon-triangle-down:before {
content: "\f05b";
} /*  */
.octicon-triangle-left:before {
content: "\f044";
} /*  */
.octicon-triangle-right:before {
content: "\f05a";
} /*  */
.octicon-triangle-up:before {
content: "\f0aa";
} /*  */
.octicon-unfold:before {
content: "\f039";
} /*  */
.octicon-unmute:before {
content: "\f0ba";
} /*  */
.octicon-versions:before {
content: "\f064";
} /*  */
.octicon-watch:before {
content: "\f0e0";
} /*  */
.octicon-remove-close:before,
.octicon-x:before { content: '\f081'} /*  */
.octicon-zap:before { content: '\26A1'} /* ⚡ */
.octicon-x:before {
content: "\f081";
} /*  */
.octicon-zap:before {
content: "\26A1";
} /* ⚡ */

View file

@ -1,217 +1,543 @@
@font-face {
font-family: 'octicons';
src: font-url('octicons.eot?#iefix') format('embedded-opentype'),
font-url('octicons.woff') format('woff'),
font-url('octicons.ttf') format('truetype'),
font-url('octicons.svg#octicons') format('svg');
font-weight: normal;
font-style: normal;
font-family: "octicons";
src: font-url("octicons.eot?#iefix") format("embedded-opentype"),
font-url("octicons.woff") format("woff"), font-url("octicons.ttf") format("truetype"),
font-url("octicons.svg#octicons") format("svg");
font-weight: normal;
font-style: normal;
}
// .octicon is optimized for 16px.
// .mega-octicon is optimized for 32px but can be used larger.
.octicon, .mega-octicon {
font: normal normal normal 16px/1 octicons;
display: inline-block;
text-decoration: none;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.octicon,
.mega-octicon {
font: normal normal normal 16px/1 octicons;
display: inline-block;
text-decoration: none;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mega-octicon {
font-size: 32px;
}
.mega-octicon { font-size: 32px; }
.octicon-alert:before { content: '\f02d'} /*  */
.octicon-arrow-down:before { content: '\f03f'} /*  */
.octicon-arrow-left:before { content: '\f040'} /*  */
.octicon-arrow-right:before { content: '\f03e'} /*  */
.octicon-arrow-small-down:before { content: '\f0a0'} /*  */
.octicon-arrow-small-left:before { content: '\f0a1'} /*  */
.octicon-arrow-small-right:before { content: '\f071'} /*  */
.octicon-arrow-small-up:before { content: '\f09f'} /*  */
.octicon-arrow-up:before { content: '\f03d'} /*  */
.octicon-alert:before {
content: "\f02d";
} /*  */
.octicon-arrow-down:before {
content: "\f03f";
} /*  */
.octicon-arrow-left:before {
content: "\f040";
} /*  */
.octicon-arrow-right:before {
content: "\f03e";
} /*  */
.octicon-arrow-small-down:before {
content: "\f0a0";
} /*  */
.octicon-arrow-small-left:before {
content: "\f0a1";
} /*  */
.octicon-arrow-small-right:before {
content: "\f071";
} /*  */
.octicon-arrow-small-up:before {
content: "\f09f";
} /*  */
.octicon-arrow-up:before {
content: "\f03d";
} /*  */
.octicon-microscope:before,
.octicon-beaker:before { content: '\f0dd'} /*  */
.octicon-bell:before { content: '\f0de'} /*  */
.octicon-book:before { content: '\f007'} /*  */
.octicon-bookmark:before { content: '\f07b'} /*  */
.octicon-briefcase:before { content: '\f0d3'} /*  */
.octicon-broadcast:before { content: '\f048'} /*  */
.octicon-browser:before { content: '\f0c5'} /*  */
.octicon-bug:before { content: '\f091'} /*  */
.octicon-calendar:before { content: '\f068'} /*  */
.octicon-check:before { content: '\f03a'} /*  */
.octicon-checklist:before { content: '\f076'} /*  */
.octicon-chevron-down:before { content: '\f0a3'} /*  */
.octicon-chevron-left:before { content: '\f0a4'} /*  */
.octicon-chevron-right:before { content: '\f078'} /*  */
.octicon-chevron-up:before { content: '\f0a2'} /*  */
.octicon-circle-slash:before { content: '\f084'} /*  */
.octicon-circuit-board:before { content: '\f0d6'} /*  */
.octicon-clippy:before { content: '\f035'} /*  */
.octicon-clock:before { content: '\f046'} /*  */
.octicon-cloud-download:before { content: '\f00b'} /*  */
.octicon-cloud-upload:before { content: '\f00c'} /*  */
.octicon-code:before { content: '\f05f'} /*  */
.octicon-color-mode:before { content: '\f065'} /*  */
.octicon-beaker:before {
content: "\f0dd";
} /*  */
.octicon-bell:before {
content: "\f0de";
} /*  */
.octicon-book:before {
content: "\f007";
} /*  */
.octicon-bookmark:before {
content: "\f07b";
} /*  */
.octicon-briefcase:before {
content: "\f0d3";
} /*  */
.octicon-broadcast:before {
content: "\f048";
} /*  */
.octicon-browser:before {
content: "\f0c5";
} /*  */
.octicon-bug:before {
content: "\f091";
} /*  */
.octicon-calendar:before {
content: "\f068";
} /*  */
.octicon-check:before {
content: "\f03a";
} /*  */
.octicon-checklist:before {
content: "\f076";
} /*  */
.octicon-chevron-down:before {
content: "\f0a3";
} /*  */
.octicon-chevron-left:before {
content: "\f0a4";
} /*  */
.octicon-chevron-right:before {
content: "\f078";
} /*  */
.octicon-chevron-up:before {
content: "\f0a2";
} /*  */
.octicon-circle-slash:before {
content: "\f084";
} /*  */
.octicon-circuit-board:before {
content: "\f0d6";
} /*  */
.octicon-clippy:before {
content: "\f035";
} /*  */
.octicon-clock:before {
content: "\f046";
} /*  */
.octicon-cloud-download:before {
content: "\f00b";
} /*  */
.octicon-cloud-upload:before {
content: "\f00c";
} /*  */
.octicon-code:before {
content: "\f05f";
} /*  */
.octicon-color-mode:before {
content: "\f065";
} /*  */
.octicon-comment-add:before,
.octicon-comment:before { content: '\f02b'} /*  */
.octicon-comment-discussion:before { content: '\f04f'} /*  */
.octicon-credit-card:before { content: '\f045'} /*  */
.octicon-dash:before { content: '\f0ca'} /*  */
.octicon-dashboard:before { content: '\f07d'} /*  */
.octicon-database:before { content: '\f096'} /*  */
.octicon-comment:before {
content: "\f02b";
} /*  */
.octicon-comment-discussion:before {
content: "\f04f";
} /*  */
.octicon-credit-card:before {
content: "\f045";
} /*  */
.octicon-dash:before {
content: "\f0ca";
} /*  */
.octicon-dashboard:before {
content: "\f07d";
} /*  */
.octicon-database:before {
content: "\f096";
} /*  */
.octicon-clone:before,
.octicon-desktop-download:before { content: '\f0dc'} /*  */
.octicon-device-camera:before { content: '\f056'} /*  */
.octicon-device-camera-video:before { content: '\f057'} /*  */
.octicon-device-desktop:before { content: '\f27c'} /*  */
.octicon-device-mobile:before { content: '\f038'} /*  */
.octicon-diff:before { content: '\f04d'} /*  */
.octicon-diff-added:before { content: '\f06b'} /*  */
.octicon-diff-ignored:before { content: '\f099'} /*  */
.octicon-diff-modified:before { content: '\f06d'} /*  */
.octicon-diff-removed:before { content: '\f06c'} /*  */
.octicon-diff-renamed:before { content: '\f06e'} /*  */
.octicon-ellipsis:before { content: '\f09a'} /*  */
.octicon-desktop-download:before {
content: "\f0dc";
} /*  */
.octicon-device-camera:before {
content: "\f056";
} /*  */
.octicon-device-camera-video:before {
content: "\f057";
} /*  */
.octicon-device-desktop:before {
content: "\f27c";
} /*  */
.octicon-device-mobile:before {
content: "\f038";
} /*  */
.octicon-diff:before {
content: "\f04d";
} /*  */
.octicon-diff-added:before {
content: "\f06b";
} /*  */
.octicon-diff-ignored:before {
content: "\f099";
} /*  */
.octicon-diff-modified:before {
content: "\f06d";
} /*  */
.octicon-diff-removed:before {
content: "\f06c";
} /*  */
.octicon-diff-renamed:before {
content: "\f06e";
} /*  */
.octicon-ellipsis:before {
content: "\f09a";
} /*  */
.octicon-eye-unwatch:before,
.octicon-eye-watch:before,
.octicon-eye:before { content: '\f04e'} /*  */
.octicon-file-binary:before { content: '\f094'} /*  */
.octicon-file-code:before { content: '\f010'} /*  */
.octicon-file-directory:before { content: '\f016'} /*  */
.octicon-file-media:before { content: '\f012'} /*  */
.octicon-file-pdf:before { content: '\f014'} /*  */
.octicon-file-submodule:before { content: '\f017'} /*  */
.octicon-file-symlink-directory:before { content: '\f0b1'} /*  */
.octicon-file-symlink-file:before { content: '\f0b0'} /*  */
.octicon-file-text:before { content: '\f011'} /*  */
.octicon-file-zip:before { content: '\f013'} /*  */
.octicon-flame:before { content: '\f0d2'} /*  */
.octicon-fold:before { content: '\f0cc'} /*  */
.octicon-gear:before { content: '\f02f'} /*  */
.octicon-gift:before { content: '\f042'} /*  */
.octicon-gist:before { content: '\f00e'} /*  */
.octicon-gist-secret:before { content: '\f08c'} /*  */
.octicon-eye:before {
content: "\f04e";
} /*  */
.octicon-file-binary:before {
content: "\f094";
} /*  */
.octicon-file-code:before {
content: "\f010";
} /*  */
.octicon-file-directory:before {
content: "\f016";
} /*  */
.octicon-file-media:before {
content: "\f012";
} /*  */
.octicon-file-pdf:before {
content: "\f014";
} /*  */
.octicon-file-submodule:before {
content: "\f017";
} /*  */
.octicon-file-symlink-directory:before {
content: "\f0b1";
} /*  */
.octicon-file-symlink-file:before {
content: "\f0b0";
} /*  */
.octicon-file-text:before {
content: "\f011";
} /*  */
.octicon-file-zip:before {
content: "\f013";
} /*  */
.octicon-flame:before {
content: "\f0d2";
} /*  */
.octicon-fold:before {
content: "\f0cc";
} /*  */
.octicon-gear:before {
content: "\f02f";
} /*  */
.octicon-gift:before {
content: "\f042";
} /*  */
.octicon-gist:before {
content: "\f00e";
} /*  */
.octicon-gist-secret:before {
content: "\f08c";
} /*  */
.octicon-git-branch-create:before,
.octicon-git-branch-delete:before,
.octicon-git-branch:before { content: '\f020'} /*  */
.octicon-git-commit:before { content: '\f01f'} /*  */
.octicon-git-compare:before { content: '\f0ac'} /*  */
.octicon-git-merge:before { content: '\f023'} /*  */
.octicon-git-branch:before {
content: "\f020";
} /*  */
.octicon-git-commit:before {
content: "\f01f";
} /*  */
.octicon-git-compare:before {
content: "\f0ac";
} /*  */
.octicon-git-merge:before {
content: "\f023";
} /*  */
.octicon-git-pull-request-abandoned:before,
.octicon-git-pull-request:before { content: '\f009'} /*  */
.octicon-globe:before { content: '\f0b6'} /*  */
.octicon-graph:before { content: '\f043'} /*  */
.octicon-heart:before { content: '\2665'} /* ♥ */
.octicon-history:before { content: '\f07e'} /*  */
.octicon-home:before { content: '\f08d'} /*  */
.octicon-horizontal-rule:before { content: '\f070'} /*  */
.octicon-hubot:before { content: '\f09d'} /*  */
.octicon-inbox:before { content: '\f0cf'} /*  */
.octicon-info:before { content: '\f059'} /*  */
.octicon-issue-closed:before { content: '\f028'} /*  */
.octicon-issue-opened:before { content: '\f026'} /*  */
.octicon-issue-reopened:before { content: '\f027'} /*  */
.octicon-jersey:before { content: '\f019'} /*  */
.octicon-key:before { content: '\f049'} /*  */
.octicon-keyboard:before { content: '\f00d'} /*  */
.octicon-law:before { content: '\f0d8'} /*  */
.octicon-light-bulb:before { content: '\f000'} /*  */
.octicon-link:before { content: '\f05c'} /*  */
.octicon-link-external:before { content: '\f07f'} /*  */
.octicon-list-ordered:before { content: '\f062'} /*  */
.octicon-list-unordered:before { content: '\f061'} /*  */
.octicon-location:before { content: '\f060'} /*  */
.octicon-git-pull-request:before {
content: "\f009";
} /*  */
.octicon-globe:before {
content: "\f0b6";
} /*  */
.octicon-graph:before {
content: "\f043";
} /*  */
.octicon-heart:before {
content: "\2665";
} /* ♥ */
.octicon-history:before {
content: "\f07e";
} /*  */
.octicon-home:before {
content: "\f08d";
} /*  */
.octicon-horizontal-rule:before {
content: "\f070";
} /*  */
.octicon-hubot:before {
content: "\f09d";
} /*  */
.octicon-inbox:before {
content: "\f0cf";
} /*  */
.octicon-info:before {
content: "\f059";
} /*  */
.octicon-issue-closed:before {
content: "\f028";
} /*  */
.octicon-issue-opened:before {
content: "\f026";
} /*  */
.octicon-issue-reopened:before {
content: "\f027";
} /*  */
.octicon-jersey:before {
content: "\f019";
} /*  */
.octicon-key:before {
content: "\f049";
} /*  */
.octicon-keyboard:before {
content: "\f00d";
} /*  */
.octicon-law:before {
content: "\f0d8";
} /*  */
.octicon-light-bulb:before {
content: "\f000";
} /*  */
.octicon-link:before {
content: "\f05c";
} /*  */
.octicon-link-external:before {
content: "\f07f";
} /*  */
.octicon-list-ordered:before {
content: "\f062";
} /*  */
.octicon-list-unordered:before {
content: "\f061";
} /*  */
.octicon-location:before {
content: "\f060";
} /*  */
.octicon-gist-private:before,
.octicon-mirror-private:before,
.octicon-git-fork-private:before,
.octicon-lock:before { content: '\f06a'} /*  */
.octicon-logo-github:before { content: '\f092'} /*  */
.octicon-mail:before { content: '\f03b'} /*  */
.octicon-mail-read:before { content: '\f03c'} /*  */
.octicon-mail-reply:before { content: '\f051'} /*  */
.octicon-mark-github:before { content: '\f00a'} /*  */
.octicon-markdown:before { content: '\f0c9'} /*  */
.octicon-megaphone:before { content: '\f077'} /*  */
.octicon-mention:before { content: '\f0be'} /*  */
.octicon-milestone:before { content: '\f075'} /*  */
.octicon-lock:before {
content: "\f06a";
} /*  */
.octicon-logo-github:before {
content: "\f092";
} /*  */
.octicon-mail:before {
content: "\f03b";
} /*  */
.octicon-mail-read:before {
content: "\f03c";
} /*  */
.octicon-mail-reply:before {
content: "\f051";
} /*  */
.octicon-mark-github:before {
content: "\f00a";
} /*  */
.octicon-markdown:before {
content: "\f0c9";
} /*  */
.octicon-megaphone:before {
content: "\f077";
} /*  */
.octicon-mention:before {
content: "\f0be";
} /*  */
.octicon-milestone:before {
content: "\f075";
} /*  */
.octicon-mirror-public:before,
.octicon-mirror:before { content: '\f024'} /*  */
.octicon-mortar-board:before { content: '\f0d7'} /*  */
.octicon-mute:before { content: '\f080'} /*  */
.octicon-no-newline:before { content: '\f09c'} /*  */
.octicon-octoface:before { content: '\f008'} /*  */
.octicon-organization:before { content: '\f037'} /*  */
.octicon-package:before { content: '\f0c4'} /*  */
.octicon-paintcan:before { content: '\f0d1'} /*  */
.octicon-pencil:before { content: '\f058'} /*  */
.octicon-mirror:before {
content: "\f024";
} /*  */
.octicon-mortar-board:before {
content: "\f0d7";
} /*  */
.octicon-mute:before {
content: "\f080";
} /*  */
.octicon-no-newline:before {
content: "\f09c";
} /*  */
.octicon-octoface:before {
content: "\f008";
} /*  */
.octicon-organization:before {
content: "\f037";
} /*  */
.octicon-package:before {
content: "\f0c4";
} /*  */
.octicon-paintcan:before {
content: "\f0d1";
} /*  */
.octicon-pencil:before {
content: "\f058";
} /*  */
.octicon-person-add:before,
.octicon-person-follow:before,
.octicon-person:before { content: '\f018'} /*  */
.octicon-pin:before { content: '\f041'} /*  */
.octicon-plug:before { content: '\f0d4'} /*  */
.octicon-person:before {
content: "\f018";
} /*  */
.octicon-pin:before {
content: "\f041";
} /*  */
.octicon-plug:before {
content: "\f0d4";
} /*  */
.octicon-repo-create:before,
.octicon-gist-new:before,
.octicon-file-directory-create:before,
.octicon-file-add:before,
.octicon-plus:before { content: '\f05d'} /*  */
.octicon-primitive-dot:before { content: '\f052'} /*  */
.octicon-primitive-square:before { content: '\f053'} /*  */
.octicon-pulse:before { content: '\f085'} /*  */
.octicon-question:before { content: '\f02c'} /*  */
.octicon-quote:before { content: '\f063'} /*  */
.octicon-radio-tower:before { content: '\f030'} /*  */
.octicon-plus:before {
content: "\f05d";
} /*  */
.octicon-primitive-dot:before {
content: "\f052";
} /*  */
.octicon-primitive-square:before {
content: "\f053";
} /*  */
.octicon-pulse:before {
content: "\f085";
} /*  */
.octicon-question:before {
content: "\f02c";
} /*  */
.octicon-quote:before {
content: "\f063";
} /*  */
.octicon-radio-tower:before {
content: "\f030";
} /*  */
.octicon-repo-delete:before,
.octicon-repo:before { content: '\f001'} /*  */
.octicon-repo-clone:before { content: '\f04c'} /*  */
.octicon-repo-force-push:before { content: '\f04a'} /*  */
.octicon-repo:before {
content: "\f001";
} /*  */
.octicon-repo-clone:before {
content: "\f04c";
} /*  */
.octicon-repo-force-push:before {
content: "\f04a";
} /*  */
.octicon-gist-fork:before,
.octicon-repo-forked:before { content: '\f002'} /*  */
.octicon-repo-pull:before { content: '\f006'} /*  */
.octicon-repo-push:before { content: '\f005'} /*  */
.octicon-rocket:before { content: '\f033'} /*  */
.octicon-rss:before { content: '\f034'} /*  */
.octicon-ruby:before { content: '\f047'} /*  */
.octicon-screen-full:before { content: '\f066'} /*  */
.octicon-screen-normal:before { content: '\f067'} /*  */
.octicon-repo-forked:before {
content: "\f002";
} /*  */
.octicon-repo-pull:before {
content: "\f006";
} /*  */
.octicon-repo-push:before {
content: "\f005";
} /*  */
.octicon-rocket:before {
content: "\f033";
} /*  */
.octicon-rss:before {
content: "\f034";
} /*  */
.octicon-ruby:before {
content: "\f047";
} /*  */
.octicon-screen-full:before {
content: "\f066";
} /*  */
.octicon-screen-normal:before {
content: "\f067";
} /*  */
.octicon-search-save:before,
.octicon-search:before { content: '\f02e'} /*  */
.octicon-server:before { content: '\f097'} /*  */
.octicon-settings:before { content: '\f07c'} /*  */
.octicon-shield:before { content: '\f0e1'} /*  */
.octicon-search:before {
content: "\f02e";
} /*  */
.octicon-server:before {
content: "\f097";
} /*  */
.octicon-settings:before {
content: "\f07c";
} /*  */
.octicon-shield:before {
content: "\f0e1";
} /*  */
.octicon-log-in:before,
.octicon-sign-in:before { content: '\f036'} /*  */
.octicon-sign-in:before {
content: "\f036";
} /*  */
.octicon-log-out:before,
.octicon-sign-out:before { content: '\f032'} /*  */
.octicon-squirrel:before { content: '\f0b2'} /*  */
.octicon-sign-out:before {
content: "\f032";
} /*  */
.octicon-squirrel:before {
content: "\f0b2";
} /*  */
.octicon-star-add:before,
.octicon-star-delete:before,
.octicon-star:before { content: '\f02a'} /*  */
.octicon-stop:before { content: '\f08f'} /*  */
.octicon-star:before {
content: "\f02a";
} /*  */
.octicon-stop:before {
content: "\f08f";
} /*  */
.octicon-repo-sync:before,
.octicon-sync:before { content: '\f087'} /*  */
.octicon-sync:before {
content: "\f087";
} /*  */
.octicon-tag-remove:before,
.octicon-tag-add:before,
.octicon-tag:before { content: '\f015'} /*  */
.octicon-telescope:before { content: '\f088'} /*  */
.octicon-terminal:before { content: '\f0c8'} /*  */
.octicon-three-bars:before { content: '\f05e'} /*  */
.octicon-thumbsdown:before { content: '\f0db'} /*  */
.octicon-thumbsup:before { content: '\f0da'} /*  */
.octicon-tools:before { content: '\f031'} /*  */
.octicon-trashcan:before { content: '\f0d0'} /*  */
.octicon-triangle-down:before { content: '\f05b'} /*  */
.octicon-triangle-left:before { content: '\f044'} /*  */
.octicon-triangle-right:before { content: '\f05a'} /*  */
.octicon-triangle-up:before { content: '\f0aa'} /*  */
.octicon-unfold:before { content: '\f039'} /*  */
.octicon-unmute:before { content: '\f0ba'} /*  */
.octicon-versions:before { content: '\f064'} /*  */
.octicon-watch:before { content: '\f0e0'} /*  */
.octicon-tag:before {
content: "\f015";
} /*  */
.octicon-telescope:before {
content: "\f088";
} /*  */
.octicon-terminal:before {
content: "\f0c8";
} /*  */
.octicon-three-bars:before {
content: "\f05e";
} /*  */
.octicon-thumbsdown:before {
content: "\f0db";
} /*  */
.octicon-thumbsup:before {
content: "\f0da";
} /*  */
.octicon-tools:before {
content: "\f031";
} /*  */
.octicon-trashcan:before {
content: "\f0d0";
} /*  */
.octicon-triangle-down:before {
content: "\f05b";
} /*  */
.octicon-triangle-left:before {
content: "\f044";
} /*  */
.octicon-triangle-right:before {
content: "\f05a";
} /*  */
.octicon-triangle-up:before {
content: "\f0aa";
} /*  */
.octicon-unfold:before {
content: "\f039";
} /*  */
.octicon-unmute:before {
content: "\f0ba";
} /*  */
.octicon-versions:before {
content: "\f064";
} /*  */
.octicon-watch:before {
content: "\f0e0";
} /*  */
.octicon-remove-close:before,
.octicon-x:before { content: '\f081'} /*  */
.octicon-zap:before { content: '\26A1'} /* ⚡ */
.octicon-x:before {
content: "\f081";
} /*  */
.octicon-zap:before {
content: "\26A1";
} /* ⚡ */

View file

@ -815,7 +815,7 @@
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-duplicate">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.936 2a2 2 0 0 0-2 2v.649h1V4a1 1 0 0 1 1-1h5.566a1 1 0 0 1 1 1v4.595a1 1 0 0 1-1 1h-.642v1h.642a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H6.936zM3.5 5.402a2 2 0 0 0-2 2v4.595a2 2 0 0 0 2 2h5.566a2 2 0 0 0 2-2V7.402a2 2 0 0 0-2-2H3.5zm-1 2a1 1 0 0 1 1-1h5.566a1 1 0 0 1 1 1v4.595a1 1 0 0 1-1 1H3.5a1 1 0 0 1-1-1V7.402z"
stroke="none" fill="#192734"></path>
stroke="none" fill="var(--icon-stroke)"></path>
</symbol>
<symbol viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-chart">

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 114 KiB

View file

@ -113,10 +113,11 @@ watch(showOptions, (val) => {
.combo-box-options {
width: 100%;
background-color: var(--white);
background-color: var(--fg-color);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-2xl);
padding: 0;
border: 1px solid var(--subtle-accent);
}
.combo-box-option {

View file

@ -1,113 +1,3 @@
<script setup>
import draggable from "vuedraggable";
import Field from "./Field.vue";
import AddFieldButton from "./AddFieldButton.vue";
import EditableInput from "./EditableInput.vue";
import { computed, ref } from "vue";
import { useStore } from "../store";
import { move_children_to_parent, confirm_dialog, is_touch_screen_device } from "../utils";
import { useMagicKeys, whenever } from "@vueuse/core";
const props = defineProps(["section", "column"]);
const store = useStore();
// delete/backspace to delete the field
const { Backspace } = useMagicKeys();
whenever(Backspace, (value) => {
if (value && selected.value && store.not_using_input) {
remove_column();
}
});
const hovered = ref(false);
const selected = computed(() => store.selected(props.column.df.name));
function add_column() {
// insert new column after the current column
let index = props.section.columns.indexOf(props.column);
props.section.columns.splice(index + 1, 0, {
df: store.get_df("Column Break"),
fields: [],
});
}
function remove_column() {
if (store.is_customize_form && props.column.df.is_custom_field == 0) {
frappe.msgprint(__("Cannot delete standard field. You can hide it if you want"));
throw "cannot delete standard field";
} else if (props.column.fields.length == 0 || store.has_standard_field(props.column)) {
delete_column();
} else {
confirm_dialog(
__("Delete Column", null, "Title of confirmation dialog"),
__(
"Are you sure you want to delete the column? All the fields in the column will be moved to the previous column.",
null,
"Confirmation dialog message"
),
() => delete_column(),
__("Delete column", null, "Button text"),
() => delete_column(true),
__("Delete entire column with fields", null, "Button text")
);
}
}
function delete_column(with_children) {
// move all fields to previous column
let columns = props.section.columns;
let index = columns.indexOf(props.column);
if (with_children && index == 0 && columns.length == 1) {
if (props.column.fields.length == 0) {
frappe.msgprint(__("Section must have at least one column"));
throw "section must have at least one column";
}
columns.unshift({
df: store.get_df("Column Break"),
fields: [],
is_first: true,
});
index++;
}
if (!with_children) {
if (index > 0) {
let prev_column = columns[index - 1];
prev_column.fields = [...prev_column.fields, ...props.column.fields];
} else {
if (props.column.fields.length == 0) {
// set next column as first column
let next_column = columns[index + 1];
if (next_column) {
next_column.is_first = true;
} else {
frappe.msgprint(__("Section must have at least one column"));
throw "section must have at least one column";
}
} else {
// create a new column if current column has fields and push fields to it
columns.unshift({
df: store.get_df("Column Break"),
fields: props.column.fields,
is_first: true,
});
index++;
}
}
}
// remove column
columns.splice(index, 1);
store.form.selected_field = null;
}
function move_columns_to_section() {
move_children_to_parent(props, "section", "column", store.current_tab);
}
</script>
<template>
<div
:class="['column', selected ? 'selected' : hovered ? 'hovered' : '']"
@ -117,35 +7,12 @@ function move_columns_to_section() {
@mouseout.stop="hovered = false"
>
<div
:class="['column-header', column.df.label ? 'has-label' : '']"
v-if="column.df.label"
class="column-header"
:hidden="!column.df.label && store.read_only"
>
<div class="column-label">
<EditableInput
:text="column.df.label"
:placeholder="__('Column Title')"
v-model="column.df.label"
/>
</div>
<div class="column-actions">
<button class="btn btn-xs btn-icon" :title="__('Add Column')" @click="add_column">
<div v-html="frappe.utils.icon('add', 'sm')"></div>
</button>
<button
v-if="section.columns.indexOf(column)"
class="btn btn-xs btn-icon"
:title="__('Move the current column & the following columns to a new section')"
@click="move_columns_to_section"
>
<div v-html="frappe.utils.icon('move', 'sm')"></div>
</button>
<button
class="btn btn-xs btn-icon"
:title="__('Remove Column')"
@click.stop="remove_column"
>
<div v-html="frappe.utils.icon('remove', 'sm')"></div>
</button>
<span>{{ column.df.label }}</span>
</div>
</div>
<div v-if="column.df.description" class="column-description">
@ -169,11 +36,7 @@ function move_columns_to_section() {
/>
</template>
</draggable>
<div
class="empty-column"
:hidden="store.read_only"
:style="store.selected(column.df.name) ? { top: '35px' } : { top: 0 }"
>
<div class="empty-column" :hidden="store.read_only">
<AddFieldButton :column="column" />
</div>
<div v-if="column.fields.length" class="add-new-field-btn">
@ -182,6 +45,30 @@ function move_columns_to_section() {
</div>
</template>
<script setup>
import draggable from "vuedraggable";
import Field from "./Field.vue";
import AddFieldButton from "./AddFieldButton.vue";
import { computed, ref } from "vue";
import { useStore } from "../store";
import { is_touch_screen_device } from "../utils";
import { useMagicKeys, whenever } from "@vueuse/core";
const props = defineProps(["section", "column"]);
const store = useStore();
// delete/backspace to delete the field
const { Backspace } = useMagicKeys();
whenever(Backspace, (value) => {
if (value && selected.value && store.not_using_input) {
remove_column();
}
});
const hovered = ref(false);
const selected = computed(() => store.selected(props.column.df.name));
</script>
<style lang="scss" scoped>
.column {
position: relative;
@ -197,35 +84,17 @@ function move_columns_to_section() {
&.hovered,
&.selected {
border-color: var(--primary);
border-color: var(--border-primary);
border-style: solid;
.btn.btn-icon {
opacity: 1 !important;
}
}
&.selected {
.column-header {
display: flex;
}
.column-container:empty {
height: 80%;
}
}
.column-header {
display: none;
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 0.5rem;
padding-left: 0.3rem;
&.has-label {
display: flex;
}
.column-label {
:deep(span) {
font-weight: 600;
@ -278,8 +147,9 @@ function move_columns_to_section() {
flex-direction: column;
align-items: center;
position: absolute;
left: 0;
top: 0;
bottom: 0;
left: 0;
gap: 5px;
width: 100%;
padding: 15px;
@ -304,7 +174,7 @@ function move_columns_to_section() {
padding: 10px 6px 5px;
button {
background-color: var(--white);
background-color: var(--fg-color);
&:hover {
background-color: var(--btn-default-hover-bg);

View file

@ -0,0 +1,129 @@
<template>
<button
ref="dropdown_btn_ref"
class="dropdown-btn btn btn-xs btn-icon"
@click.stop="toggle_fieldtype_options"
>
<slot>
<div v-html="frappe.utils.icon('dot-horizontal', 'sm')" />
</slot>
<Teleport to="#autocomplete-area">
<div class="dropdown" ref="dropdown_ref">
<div v-show="show" class="dropdown-options">
<div v-for="group in groups" :key="group.key" class="groups">
<div v-if="group.group" class="group-title">
{{ group.group }}
</div>
<div
class="dropdown-option"
v-for="item in group.items"
:key="item.label"
:title="item.tooltip"
>
<button class="dropdown-item" @click.stop="action(item.onClick)">
{{ item.label }}
</button>
</div>
</div>
</div>
</div>
</Teleport>
</button>
</template>
<script setup>
import { createPopper } from "@popperjs/core";
import { nextTick, ref, computed } from "vue";
import { onClickOutside } from "@vueuse/core";
const props = defineProps({
options: {
type: Array,
required: true,
},
placement: {
type: String,
default: "bottom-end",
},
});
const show = ref(false);
const dropdown_btn_ref = ref(null);
const dropdown_ref = ref(null);
const popper = ref(null);
onClickOutside(dropdown_btn_ref, () => (show.value = false), { ignore: [dropdown_ref] });
const groups = computed(() => {
let _groups = props.options[0]?.group ? props.options : [{ group: "", items: props.options }];
return _groups.map((group, i) => {
return {
key: i,
group: group.group,
items: group.items,
};
});
});
function setupPopper() {
if (!popper.value) {
popper.value = createPopper(dropdown_btn_ref.value, dropdown_ref.value, {
placement: props.placement,
modifiers: [
{
name: "offset",
options: {
offset: [0, 4],
},
},
],
});
} else {
popper.value.update();
}
}
function toggle_fieldtype_options() {
show.value = !show.value;
nextTick(() => setupPopper());
}
function action(clickEvent) {
clickEvent && clickEvent();
show.value = false;
}
</script>
<style lang="scss" scoped>
.groups {
padding: 5px;
.group-title {
display: flex;
align-items: center;
padding: 4px 8px;
font-size: smaller;
font-weight: 600;
text-transform: uppercase;
color: var(--disabled-text-color);
}
}
.dropdown-btn {
&:hover {
background-color: var(--bg-light-gray);
}
}
.dropdown-options {
background-color: var(--fg-color);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-2xl);
padding: 4px;
border: 1px solid var(--subtle-accent);
}
.dropdown {
z-index: 100;
}
</style>

View file

@ -166,7 +166,7 @@ onMounted(() => selected.value && label_input.value.focus_on_label());
&.hovered,
&.selected {
border-color: var(--primary);
border-color: var(--border-primary);
.btn.btn-icon {
opacity: 1 !important;
}

View file

@ -6,7 +6,7 @@
class="search-input form-control"
type="text"
:placeholder="__('Search properties...')"
@input="event => $emit('update:modelValue', event.target.value)"
@input="(event) => $emit('update:modelValue', event.target.value)"
/>
<span class="search-icon">
<div v-html="frappe.utils.icon('search', 'sm')"></div>

View file

@ -1,10 +1,87 @@
<template>
<div
class="form-section-container"
:style="{ borderBottom: props.section.df.hide_border ? 'none' : '' }"
>
<div
:class="[
'form-section',
hovered ? 'hovered' : '',
store.selected(section.df.name) ? 'selected' : '',
]"
:title="section.df.fieldname"
@click.stop="select_section"
@mouseover.stop="hovered = true"
@mouseout.stop="hovered = false"
>
<div
:class="[
'section-header',
section.df.label || section.df.collapsible ? 'has-label' : '',
collapsed ? 'collapsed' : '',
]"
:hidden="!section.df.label && store.read_only"
>
<div class="section-label">
<EditableInput
:text="section.df.label"
:placeholder="__('Section Title')"
v-model="section.df.label"
/>
<div
v-if="section.df.collapsible"
class="collapse-indicator"
v-html="frappe.utils.icon(collapsed ? 'down' : 'up-line', 'sm')"
></div>
</div>
<Dropdown v-if="!store.read_only" :options="options" @click.stop />
</div>
<div v-if="section.df.description" class="section-description">
{{ section.df.description }}
</div>
<div
class="section-columns"
:class="{
hidden: section.df.collapsible && collapsed,
'has-one-column': section.columns.length === 1,
}"
>
<draggable
class="section-columns-container"
v-model="section.columns"
group="columns"
item-key="id"
:delay="is_touch_screen_device() ? 200 : 0"
:animation="200"
:easing="store.get_animation"
:disabled="store.read_only"
>
<template #item="{ element }">
<Column
:section="section"
:column="element"
:data-is-user-generated="store.is_user_generated_field(element)"
/>
</template>
</draggable>
</div>
</div>
</div>
</template>
<script setup>
import draggable from "vuedraggable";
import Column from "./Column.vue";
import EditableInput from "./EditableInput.vue";
import Dropdown from "./Dropdown.vue";
import { ref, computed } from "vue";
import { useStore } from "../store";
import { section_boilerplate, move_children_to_parent, confirm_dialog, is_touch_screen_device } from "../utils";
import {
section_boilerplate,
move_children_to_parent,
confirm_dialog,
is_touch_screen_device,
} from "../utils";
import { useMagicKeys, whenever } from "@vueuse/core";
const props = defineProps(["tab", "section"]);
@ -21,7 +98,9 @@ whenever(Backspace, (value) => {
const hovered = ref(false);
const collapsed = ref(false);
const selected = computed(() => store.selected(props.section.df.name));
const column = computed(() => props.section.columns[props.section.columns.length - 1]);
// section
function add_section_above() {
let index = props.tab.sections.indexOf(props.section);
props.tab.sections.splice(index, 0, section_boilerplate());
@ -97,103 +176,130 @@ function move_sections_to_tab() {
// activate tab
store.form.active_tab = new_tab;
}
</script>
<template>
<div
class="form-section-container"
:style="{ borderBottom: props.section.df.hide_border ? 'none' : '' }"
>
<div
:class="[
'form-section',
hovered ? 'hovered' : '',
store.selected(section.df.name) ? 'selected' : '',
]"
:title="section.df.fieldname"
@click.stop="select_section"
@mouseover.stop="hovered = true"
@mouseout.stop="hovered = false"
>
<div
:class="[
'section-header',
section.df.label || section.df.collapsible ? 'has-label' : '',
collapsed ? 'collapsed' : '',
]"
:hidden="!section.df.label && store.read_only"
>
<div class="section-label">
<EditableInput
:text="section.df.label"
:placeholder="__('Section Title')"
v-model="section.df.label"
/>
<div
v-if="section.df.collapsible"
class="collapse-indicator"
v-html="frappe.utils.icon(collapsed ? 'down' : 'up-line', 'sm')"
></div>
</div>
<div class="section-actions" :hidden="store.read_only">
<button
class="btn btn-xs btn-section"
:title="__('Add section above')"
@click="add_section_above"
>
<div v-html="frappe.utils.icon('add', 'sm')"></div>
</button>
<button
v-if="tab.sections.indexOf(section)"
class="btn btn-xs btn-section"
:title="
__('Move the current section and the following sections to a new tab')
"
@click="move_sections_to_tab"
>
<div v-html="frappe.utils.icon('move', 'sm')"></div>
</button>
<button
class="btn btn-xs btn-section"
:title="__('Remove section')"
@click.stop="remove_section"
>
<div v-html="frappe.utils.icon('remove', 'sm')"></div>
</button>
</div>
</div>
<div v-if="section.df.description" class="section-description">
{{ section.df.description }}
</div>
<div
class="section-columns"
:class="{
hidden: section.df.collapsible && collapsed,
'has-one-column': section.columns.length === 1,
}"
>
<draggable
class="section-columns-container"
v-model="section.columns"
group="columns"
item-key="id"
:delay="is_touch_screen_device() ? 200 : 0"
:animation="200"
:easing="store.get_animation"
:disabled="store.read_only"
>
<template #item="{ element }">
<Column
:section="section"
:column="element"
:data-is-user-generated="store.is_user_generated_field(element)"
/>
</template>
</draggable>
</div>
</div>
</div>
</template>
// column
function add_column() {
props.section.columns.push({
fields: [],
df: store.get_df("Column Break"),
});
}
function remove_column() {
if (store.is_customize_form && column.value.df.is_custom_field == 0) {
frappe.msgprint(__("Cannot delete standard field. You can hide it if you want"));
throw "cannot delete standard field";
} else if (column.value.fields.length == 0 || store.has_standard_field(column.value)) {
delete_column();
} else {
confirm_dialog(
__("Delete Column", null, "Title of confirmation dialog"),
__(
"Are you sure you want to delete the column? All the fields in the column will be moved to the previous column.",
null,
"Confirmation dialog message"
),
() => delete_column(),
__("Delete column", null, "Button text"),
() => delete_column(true),
__("Delete entire column with fields", null, "Button text")
);
}
}
function delete_column(with_children) {
// move all fields to previous column
let columns = props.section.columns;
let index = columns.length - 1;
if (with_children && index == 0 && columns.length == 1) {
if (column.value.fields.length == 0) {
frappe.msgprint(__("Section must have at least one column"));
throw "section must have at least one column";
}
columns.unshift({
df: store.get_df("Column Break"),
fields: [],
is_first: true,
});
index++;
}
if (!with_children) {
if (index > 0) {
let prev_column = columns[index - 1];
prev_column.fields = [...prev_column.fields, ...column.value.fields];
} else {
if (column.value.fields.length == 0) {
// set next column as first column
let next_column = columns[index + 1];
if (next_column) {
next_column.is_first = true;
} else {
frappe.msgprint(__("Section must have at least one column"));
throw "section must have at least one column";
}
} else {
// create a new column if current column has fields and push fields to it
columns.unshift({
df: store.get_df("Column Break"),
fields: column.value.fields,
is_first: true,
});
index++;
}
}
}
// remove column
columns.splice(index, 1);
store.form.selected_field = null;
}
const options = computed(() => {
let groups = [
{
group: "Section",
items: [
{ label: "Add section above", onClick: add_section_above },
{ label: "Remove section", onClick: remove_section },
],
},
{
group: "Column",
items: [{ label: "Add column", onClick: add_column }],
},
];
// add remove column option if there are more than one columns
if (props.section.columns.length > 1) {
groups[1].items.push({
label: "Remove column",
tooltip: "Remove last column",
onClick: remove_column,
});
} else if (props.section.columns[0].fields.length) {
// add remove all fields option if there is only one column and it has fields
groups[1].items.push({
label: "Empty column",
tooltip: "Remove all fields in the column",
onClick: () => delete_column(true),
});
}
// add move to tab option if the current section is not the first section
if (props.tab.sections.indexOf(props.section) > 0) {
groups[0].items.push({
label: "Move sections to new tab",
tooltip: "Move current and all subsequent sections to a new tab",
onClick: move_sections_to_tab,
});
}
return groups;
});
</script>
<style lang="scss" scoped>
.form-section-container {
@ -218,15 +324,11 @@ function move_sections_to_tab() {
&.hovered,
&.selected {
border-color: var(--primary);
}
&.selected .section-header {
display: flex;
border-color: var(--border-primary);
}
.section-header {
display: none;
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 0.75rem;
@ -254,16 +356,21 @@ function move_sections_to_tab() {
.section-actions {
display: flex;
gap: 4px;
align-items: center;
}
.btn-section {
padding: var(--padding-xs);
box-shadow: none;
// .btn-section {
// padding: var(--padding-xs);
// box-shadow: none;
&:hover {
background-color: var(--bg-light-gray);
}
// &:hover {
// background-color: var(--bg-light-gray);
// }
// }
.btn-section {
display: inline-flex;
gap: 2px;
}
}

View file

@ -13,7 +13,7 @@ const store = useStore();
const { Backspace } = useMagicKeys();
whenever(Backspace, (value) => {
if (value && selected.value && store.not_using_input) {
remove_tab(store.current_tab, '', true);
remove_tab(store.current_tab, "", true);
}
});
@ -45,12 +45,10 @@ function add_new_section() {
function is_tab_empty(tab) {
// check if sections have columns and it contains fields
return !tab.sections.some((section) =>
section.columns.some((column) => column.fields.length)
);
return !tab.sections.some((section) => section.columns.some((column) => column.fields.length));
}
function remove_tab(tab, event, force=false) {
function remove_tab(tab, event, force = false) {
// is remove_tab_btn is not visible then return
if (!event?.currentTarget?.offsetParent && !force) return;
@ -270,7 +268,7 @@ function delete_tab(tab, with_children) {
color: var(--text-color);
&::before {
border-color: var(--primary);
border-color: var(--border-primary);
}
}

View file

@ -4,10 +4,7 @@ const props = defineProps(["df", "value"]);
</script>
<template>
<div
class="control frappe-control editable"
:data-fieldtype="df.fieldtype"
>
<div class="control frappe-control editable" :data-fieldtype="df.fieldtype">
<!-- label -->
<div class="field-controls">
<h4 v-if="df.fieldtype == 'Heading'">
@ -28,5 +25,4 @@ const props = defineProps(["df", "value"]);
h4 {
margin-bottom: 0px;
}
</style>

View file

@ -20,7 +20,7 @@ let slots = useSlots();
type="checkbox"
:checked="value"
:disabled="read_only"
@change="event => $emit('update:modelValue', event.target.checked)"
@change="(event) => $emit('update:modelValue', event.target.checked)"
/>
<span class="label-area" :class="{ reqd: df.reqd }">{{ df.label }}</span>
</label>
@ -31,7 +31,8 @@ let slots = useSlots();
</template>
<style lang="scss" scoped>
label, input {
label,
input {
margin-bottom: 0 !important;
cursor: pointer;
}

View file

@ -7,40 +7,36 @@ let emit = defineEmits(["update:modelValue"]);
let slots = useSlots();
let code = ref(null);
let code_control = ref(null);
let update_control = ref(true);
let code_control = computed(() => {
if (!code.value) return;
code.value.innerHTML = "";
return frappe.ui.form.make_control({
parent: code.value,
df: {
...props.df,
fieldtype: "Code",
hidden: 0,
read_only: props.read_only,
change: () => {
if (update_control.value) {
content.value = code_control.value.get_value();
}
update_control.value = true;
},
},
value: content.value,
disabled: Boolean(slots.label) || props.read_only,
render_input: true,
only_input: Boolean(slots.label),
});
});
let content = computed({
get: () => props.modelValue,
set: (value) => emit("update:modelValue", value),
});
onMounted(() => {
if (code.value) code_control.value;
if (code.value) {
code_control.value = frappe.ui.form.make_control({
parent: code.value,
df: {
...props.df,
fieldtype: "Code",
hidden: 0,
read_only: props.read_only,
change: () => {
if (update_control.value) {
content.value = code_control.value.get_value();
}
update_control.value = true;
},
},
value: content.value,
disabled: Boolean(slots.label) || props.read_only,
render_input: true,
only_input: Boolean(slots.label),
});
}
});
watch(

View file

@ -23,10 +23,7 @@ if (props.df.fieldtype === "Icon") {
</script>
<template>
<div
class="control frappe-control"
:class="{ editable: slots.label }"
>
<div class="control frappe-control" :class="{ editable: slots.label }">
<!-- label -->
<div v-if="slots.label" class="field-controls">
<slot name="label" />
@ -49,7 +46,7 @@ if (props.df.fieldtype === "Icon") {
type="text"
:value="value"
:disabled="read_only || df.read_only"
@input="event => $emit('update:modelValue', event.target.value)"
@input="(event) => $emit('update:modelValue', event.target.value)"
/>
<input
v-if="slots.label && df.fieldtype === 'Barcode'"

View file

@ -13,20 +13,22 @@ function get_options() {
if (typeof options == "string") {
options = options.split("\n") || "";
options = options.map(opt => {
options = options.map((opt) => {
return { label: __(opt), value: opt };
});
}
if (options?.length && typeof options[0] == "string") {
options = options.map(opt => {
options = options.map((opt) => {
return { label: __(opt), value: opt };
});
}
if (props.df.fieldname == "fieldtype") {
if (!in_list(frappe.model.layout_fields, props.modelValue)) {
options = options && options.filter(opt => !in_list(frappe.model.layout_fields, opt.value));
options =
options &&
options.filter((opt) => !in_list(frappe.model.layout_fields, opt.value));
} else {
options = [{ label: __(props.modelValue), value: props.modelValue }];
}
@ -56,17 +58,17 @@ let select_control = computed(() => {
content.value = select_control.value.get_value();
}
update_control.value = true;
}
},
},
value: content.value,
render_input: true,
only_input: Boolean(slots.label) || props.no_label
only_input: Boolean(slots.label) || props.no_label,
});
});
let content = computed({
get: () => props.modelValue,
set: value => emit("update:modelValue", value)
set: (value) => emit("update:modelValue", value),
});
onMounted(() => {
@ -75,15 +77,18 @@ onMounted(() => {
watch(
() => content.value,
value => {
(value) => {
update_control.value = false;
select_control.value?.set_value(value);
}
);
watch(() => props.df.options, () => {
select_control.value;
})
watch(
() => props.df.options,
() => {
select_control.value;
}
);
</script>
<template>

View file

@ -38,7 +38,7 @@ let height = computed(() => {
type="text"
:value="value"
:disabled="read_only || df.read_only"
@input="event => $emit('update:modelValue', event.target.value)"
@input="(event) => $emit('update:modelValue', event.target.value)"
/>
<!-- description -->

View file

@ -28,9 +28,7 @@ function open_in_editor(location) {
}
function error_component(error, i) {
let location = data.value.error.errors[i].location;
let location_string = `${location.file}:${location.line}:${
location.column
}`;
let location_string = `${location.file}:${location.line}:${location.column}`;
let template = error.replace(
" > " + location_string,
` &gt; <a class="file-link" @click="open">${location_string}</a>`
@ -41,11 +39,11 @@ function error_component(error, i) {
methods: {
open() {
frappe.realtime.emit("open_in_editor", location);
}
}
},
},
};
}
defineExpose({show, hide});
defineExpose({ show, hide });
</script>
<style scoped>
@ -58,8 +56,7 @@ defineExpose({show, hide});
z-index: 9999;
margin: 0;
background: rgba(0, 0, 0, 0.66);
--monospace: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
monospace;
--monospace: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
--dim: var(--gray-400);
}
.window {

View file

@ -1,13 +1,7 @@
<template>
<div
v-if="is_shown"
class="flex justify-between build-success-message align-center"
>
<div v-if="is_shown" class="flex justify-between build-success-message align-center">
Compiled successfully
<a
v-if="!live_reload"
class="ml-4 text-white underline" href="/" @click.prevent="reload"
>
<a v-if="!live_reload" class="ml-4 text-white underline" href="/" @click.prevent="reload">
Refresh
</a>
</div>
@ -43,7 +37,7 @@ function reload() {
window.location.reload();
}
defineExpose({show, hide});
defineExpose({ show, hide });
</script>
<style scoped>

View file

@ -1,11 +1,7 @@
<template>
<div class="file-browser">
<div>
<a
href=""
class="text-muted text-medium"
@click.prevent="emit('hide-browser')"
>
<a href="" class="text-muted text-medium" @click.prevent="emit('hide-browser')">
{{ __("← Back to upload files") }}
</a>
</div>
@ -23,8 +19,8 @@
class="tree with-skeleton"
:node="node"
:selected_node="selected_node"
@node-click="n => toggle_node(n)"
@load-more="n => load_more(n)"
@node-click="(n) => toggle_node(n)"
@load-more="(n) => load_more(n)"
/>
</div>
</div>
@ -48,7 +44,7 @@ let node = ref({
fetching: false,
fetched: false,
open: false,
filtered: true
filtered: true,
});
let selected_node = ref({});
let search_text = ref("");
@ -61,16 +57,14 @@ function toggle_node(node) {
node.fetching = true;
node.children_start = 0;
node.children_loading = false;
get_files_in_folder(node.value, 0).then(
({ files, has_more }) => {
node.open = true;
node.children = files;
node.fetched = true;
node.fetching = false;
node.children_start += page_length.value;
node.has_more_children = has_more;
}
);
get_files_in_folder(node.value, 0).then(({ files, has_more }) => {
node.open = true;
node.children = files;
node.fetched = true;
node.fetching = false;
node.children_start += page_length.value;
node.has_more_children = has_more;
});
} else {
node.open = !node.open;
select_node(node);
@ -80,14 +74,12 @@ function load_more(node) {
if (node.has_more_children) {
let start = node.children_start;
node.children_loading = true;
get_files_in_folder(node.value, start).then(
({ files, has_more }) => {
node.children = node.children.concat(files);
node.children_start += page_length.value;
node.has_more_children = has_more;
node.children_loading = false;
}
);
get_files_in_folder(node.value, start).then(({ files, has_more }) => {
node.children = node.children.concat(files);
node.children_start += page_length.value;
node.has_more_children = has_more;
node.children_loading = false;
});
}
}
function select_node(node) {
@ -100,9 +92,9 @@ function get_files_in_folder(folder, start) {
.call("frappe.core.api.file.get_files_in_folder", {
folder,
start,
page_length: page_length.value
page_length: page_length.value,
})
.then(r => {
.then((r) => {
let { files = [], has_more = false } = r.message || {};
files.sort((a, b) => {
if (a.is_folder && b.is_folder) {
@ -116,7 +108,7 @@ function get_files_in_folder(folder, start) {
}
return 0;
});
files = files.map(file => make_file_node(file));
files = files.map((file) => make_file_node(file));
return { files, has_more };
});
}
@ -127,15 +119,12 @@ function search_by_name() {
}
if (search_text.value.length < 3) return;
frappe
.call(
"frappe.core.api.file.get_files_by_search_text",
{
text: search_text.value
}
)
.then(r => {
.call("frappe.core.api.file.get_files_by_search_text", {
text: search_text.value,
})
.then((r) => {
let files = r.message || [];
files = files.map(file => make_file_node(file));
files = files.map((file) => make_file_node(file));
if (!folder_node.value) {
folder_node.value = node.value;
}
@ -145,7 +134,7 @@ function search_by_name() {
children: files,
by_search: true,
open: true,
filtered: true
filtered: true,
};
});
}
@ -164,7 +153,7 @@ function make_file_node(file) {
children_start: 0,
open: false,
fetching: false,
filtered: true
filtered: true,
};
}

View file

@ -1,13 +1,8 @@
<template>
<div class="file-preview">
<div class="file-icon">
<img
v-if="is_image"
:src="src"
:alt="file.name"
>
<div class="fallback" v-else v-html="frappe.utils.icon('file', 'md')">
</div>
<img v-if="is_image" :src="src" :alt="file.name" />
<div class="fallback" v-else v-html="frappe.utils.icon('file', 'md')"></div>
</div>
<div>
<div>
@ -24,8 +19,20 @@
</div>
<div class="flex config-area">
<label v-if="is_optimizable" class="frappe-checkbox"><input type="checkbox" :checked="optimize" @change="emit('toggle_optimize')">{{ __('Optimize') }}</label>
<label class="frappe-checkbox"><input type="checkbox" :checked="file.private" @change="emit('toggle_private')">{{ __('Private') }}</label>
<label v-if="is_optimizable" class="frappe-checkbox"
><input
type="checkbox"
:checked="optimize"
@change="emit('toggle_optimize')"
/>{{ __("Optimize") }}</label
>
<label class="frappe-checkbox"
><input
type="checkbox"
:checked="file.private"
@change="emit('toggle_private')"
/>{{ __("Private") }}</label
>
</div>
<div>
<span v-if="file.error_message" class="file-error text-danger">
@ -45,8 +52,18 @@
<div v-if="uploaded" v-html="frappe.utils.icon('solid-success', 'lg')"></div>
<div v-if="file.failed" v-html="frappe.utils.icon('solid-error', 'lg')"></div>
<div class="file-action-buttons">
<button v-if="is_cropable" class="btn btn-crop muted" @click="emit('toggle_image_cropper')" v-html="frappe.utils.icon('crop', 'md')"></button>
<button v-if="!uploaded && !file.uploading && !file.failed" class="btn muted" @click="emit('remove')" v-html="frappe.utils.icon('delete', 'md')"></button>
<button
v-if="is_cropable"
class="btn btn-crop muted"
@click="emit('toggle_image_cropper')"
v-html="frappe.utils.icon('crop', 'md')"
></button>
<button
v-if="!uploaded && !file.uploading && !file.failed"
class="btn muted"
@click="emit('remove')"
v-html="frappe.utils.icon('delete', 'md')"
></button>
</div>
</div>
</div>
@ -79,15 +96,20 @@ let uploaded = computed(() => {
return props.file.request_succeeded;
});
let is_image = computed(() => {
return props.file.file_obj.type.startsWith('image');
return props.file.file_obj.type.startsWith("image");
});
let is_optimizable = computed(() => {
let is_svg = props.file.file_obj.type == 'image/svg+xml';
let is_svg = props.file.file_obj.type == "image/svg+xml";
return is_image.value && !is_svg && !uploaded.value && !props.file.failed;
});
let is_cropable = computed(() => {
let croppable_types = ['image/jpeg', 'image/png'];
return !uploaded.value && !props.file.uploading && !props.file.failed && croppable_types.includes(props.file.file_obj.type);
let croppable_types = ["image/jpeg", "image/png"];
return (
!uploaded.value &&
!props.file.uploading &&
!props.file.failed &&
croppable_types.includes(props.file.file_obj.type)
);
});
let progress = computed(() => {
let value = Math.round((props.file.progress * 100) / props.file.total);
@ -102,7 +124,7 @@ onMounted(() => {
if (is_image.value) {
if (window.FileReader) {
let fr = new FileReader();
fr.onload = () => src.value = fr.result;
fr.onload = () => (src.value = fr.result);
fr.readAsDataURL(props.file.file_obj);
}
}

View file

@ -1,5 +1,6 @@
<template>
<div class="file-uploader"
<div
class="file-uploader"
@dragover.prevent="dragover"
@dragleave.prevent="dragleave"
@drop.prevent="dropfiles"
@ -10,19 +11,50 @@
>
<div v-if="!is_dragging">
<div class="text-center">
{{ __('Drag and drop files here or upload from') }}
{{ __("Drag and drop files here or upload from") }}
</div>
<div class="mt-2 text-center">
<button class="btn btn-file-upload" @click="browse_files">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="15" cy="15" r="15" fill="var(--subtle-fg)"/>
<path d="M13.5 22V19" stroke="var(--text-color)" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16.5 22V19" stroke="var(--text-color)" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.5 22H19.5" stroke="var(--text-color)" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.5 16H22.5" stroke="var(--text-color)" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21 8H9C8.17157 8 7.5 8.67157 7.5 9.5V17.5C7.5 18.3284 8.17157 19 9 19H21C21.8284 19 22.5 18.3284 22.5 17.5V9.5C22.5 8.67157 21.8284 8 21 8Z" stroke="var(--text-color)" stroke-linecap="round" stroke-linejoin="round"/>
<svg
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="15" cy="15" r="15" fill="var(--subtle-fg)" />
<path
d="M13.5 22V19"
stroke="var(--text-color)"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M16.5 22V19"
stroke="var(--text-color)"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M10.5 22H19.5"
stroke="var(--text-color)"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M7.5 16H22.5"
stroke="var(--text-color)"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M21 8H9C8.17157 8 7.5 8.67157 7.5 9.5V17.5C7.5 18.3284 8.17157 19 9 19H21C21.8284 19 22.5 18.3284 22.5 17.5V9.5C22.5 8.67157 21.8284 8 21 8Z"
stroke="var(--text-color)"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<div class="mt-1">{{ __('My Device') }}</div>
<div class="mt-1">{{ __("My Device") }}</div>
</button>
<input
type="file"
@ -31,37 +63,105 @@
@change="on_file_input"
:multiple="allow_multiple"
:accept="(restrictions.allowed_file_types || []).join(', ')"
/>
<button
class="btn btn-file-upload"
v-if="!disable_file_browser"
@click="show_file_browser = true"
>
<button class="btn btn-file-upload" v-if="!disable_file_browser" @click="show_file_browser = true">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="15" cy="15" r="15" fill="var(--subtle-fg)"/>
<path d="M13.0245 11.5H8C7.72386 11.5 7.5 11.7239 7.5 12V20C7.5 21.1046 8.39543 22 9.5 22H20.5C21.6046 22 22.5 21.1046 22.5 20V14.5C22.5 14.2239 22.2761 14 22 14H15.2169C15.0492 14 14.8926 13.9159 14.8 13.776L13.4414 11.724C13.3488 11.5841 13.1922 11.5 13.0245 11.5Z" stroke="var(--text-color)" stroke-miterlimit="10" stroke-linecap="square"/>
<path d="M8.87939 9.5V8.5C8.87939 8.22386 9.10325 8 9.37939 8H20.6208C20.8969 8 21.1208 8.22386 21.1208 8.5V12" stroke="var(--text-color)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<svg
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="15" cy="15" r="15" fill="var(--subtle-fg)" />
<path
d="M13.0245 11.5H8C7.72386 11.5 7.5 11.7239 7.5 12V20C7.5 21.1046 8.39543 22 9.5 22H20.5C21.6046 22 22.5 21.1046 22.5 20V14.5C22.5 14.2239 22.2761 14 22 14H15.2169C15.0492 14 14.8926 13.9159 14.8 13.776L13.4414 11.724C13.3488 11.5841 13.1922 11.5 13.0245 11.5Z"
stroke="var(--text-color)"
stroke-miterlimit="10"
stroke-linecap="square"
/>
<path
d="M8.87939 9.5V8.5C8.87939 8.22386 9.10325 8 9.37939 8H20.6208C20.8969 8 21.1208 8.22386 21.1208 8.5V12"
stroke="var(--text-color)"
stroke-miterlimit="10"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<div class="mt-1">{{ __('Library') }}</div>
<div class="mt-1">{{ __("Library") }}</div>
</button>
<button class="btn btn-file-upload" v-if="allow_web_link" @click="show_web_link = true">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="15" cy="15" r="15" fill="var(--subtle-fg)"/>
<path d="M12.0469 17.9543L17.9558 12.0454" stroke="var(--text-color)" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.8184 11.4547L15.7943 9.47873C16.4212 8.85205 17.2714 8.5 18.1578 8.5C19.0443 8.5 19.8945 8.85205 20.5214 9.47873V9.47873C21.1481 10.1057 21.5001 10.9558 21.5001 11.8423C21.5001 12.7287 21.1481 13.5789 20.5214 14.2058L18.5455 16.1818" stroke="var(--text-color)" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.4547 13.8184L9.47873 15.7943C8.85205 16.4212 8.5 17.2714 8.5 18.1578C8.5 19.0443 8.85205 19.8945 9.47873 20.5214V20.5214C10.1057 21.1481 10.9558 21.5001 11.8423 21.5001C12.7287 21.5001 13.5789 21.1481 14.2058 20.5214L16.1818 18.5455" stroke="var(--text-color)" stroke-linecap="round" stroke-linejoin="round"/>
<button
class="btn btn-file-upload"
v-if="allow_web_link"
@click="show_web_link = true"
>
<svg
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="15" cy="15" r="15" fill="var(--subtle-fg)" />
<path
d="M12.0469 17.9543L17.9558 12.0454"
stroke="var(--text-color)"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M13.8184 11.4547L15.7943 9.47873C16.4212 8.85205 17.2714 8.5 18.1578 8.5C19.0443 8.5 19.8945 8.85205 20.5214 9.47873V9.47873C21.1481 10.1057 21.5001 10.9558 21.5001 11.8423C21.5001 12.7287 21.1481 13.5789 20.5214 14.2058L18.5455 16.1818"
stroke="var(--text-color)"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M11.4547 13.8184L9.47873 15.7943C8.85205 16.4212 8.5 17.2714 8.5 18.1578C8.5 19.0443 8.85205 19.8945 9.47873 20.5214V20.5214C10.1057 21.1481 10.9558 21.5001 11.8423 21.5001C12.7287 21.5001 13.5789 21.1481 14.2058 20.5214L16.1818 18.5455"
stroke="var(--text-color)"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<div class="mt-1">{{ __('Link') }}</div>
<div class="mt-1">{{ __("Link") }}</div>
</button>
<button v-if="allow_take_photo" class="btn btn-file-upload" @click="capture_image">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="15" cy="15" r="15" fill="var(--subtle-fg)"/>
<path d="M11.5 10.5H9.5C8.67157 10.5 8 11.1716 8 12V20C8 20.8284 8.67157 21.5 9.5 21.5H20.5C21.3284 21.5 22 20.8284 22 20V12C22 11.1716 21.3284 10.5 20.5 10.5H18.5L17.3 8.9C17.1111 8.64819 16.8148 8.5 16.5 8.5H13.5C13.1852 8.5 12.8889 8.64819 12.7 8.9L11.5 10.5Z" stroke="var(--text-color)" stroke-linejoin="round"/>
<circle cx="15" cy="16" r="2.5" stroke="var(--text-color)"/>
<button
v-if="allow_take_photo"
class="btn btn-file-upload"
@click="capture_image"
>
<svg
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="15" cy="15" r="15" fill="var(--subtle-fg)" />
<path
d="M11.5 10.5H9.5C8.67157 10.5 8 11.1716 8 12V20C8 20.8284 8.67157 21.5 9.5 21.5H20.5C21.3284 21.5 22 20.8284 22 20V12C22 11.1716 21.3284 10.5 20.5 10.5H18.5L17.3 8.9C17.1111 8.64819 16.8148 8.5 16.5 8.5H13.5C13.1852 8.5 12.8889 8.64819 12.7 8.9L11.5 10.5Z"
stroke="var(--text-color)"
stroke-linejoin="round"
/>
<circle cx="15" cy="16" r="2.5" stroke="var(--text-color)" />
</svg>
<div class="mt-1">{{ __('Camera') }}</div>
<div class="mt-1">{{ __("Camera") }}</div>
</button>
<button v-if="google_drive_settings.enabled" class="btn btn-file-upload" @click="show_google_drive_picker">
<button
v-if="google_drive_settings.enabled"
class="btn btn-file-upload"
@click="show_google_drive_picker"
>
<svg width="30" height="30">
<image href="/assets/frappe/icons/social/google_drive.svg" width="30" height="30"/>
<image
href="/assets/frappe/icons/social/google_drive.svg"
width="30"
height="30"
/>
</svg>
<div class="mt-1">{{ __('Google Drive') }}</div>
<div class="mt-1">{{ __("Google Drive") }}</div>
</button>
</div>
<div class="text-muted text-medium text-center">
@ -69,10 +169,13 @@
</div>
</div>
<div v-else>
{{ __('Drop files here') }}
{{ __("Drop files here") }}
</div>
</div>
<div class="file-preview-area" v-show="files.length && !show_file_browser && !show_web_link">
<div
class="file-preview-area"
v-show="files.length && !show_file_browser && !show_web_link"
>
<div class="file-preview-container" v-if="!show_image_cropper">
<FilePreview
v-for="(file, i) in files"
@ -85,19 +188,16 @@
/>
</div>
<div class="flex align-center" v-if="show_upload_button && currently_uploading === -1">
<button
class="btn btn-primary btn-sm margin-right"
@click="upload_files"
>
<button class="btn btn-primary btn-sm margin-right" @click="upload_files">
<span v-if="files.length === 1">
{{ __('Upload file') }}
{{ __("Upload file") }}
</span>
<span v-else>
{{ __('Upload {0} files', [files.length]) }}
{{ __("Upload {0} files", [files.length]) }}
</span>
</button>
<div class="text-muted text-medium">
{{ __('Click on the lock icon to toggle public/private') }}
{{ __("Click on the lock icon to toggle public/private") }}
</div>
</div>
</div>
@ -106,60 +206,56 @@
:file="files[crop_image_with_index]"
:fixed_aspect_ratio="restrictions.crop_image_aspect_ratio"
@toggle_image_cropper="toggle_image_cropper(-1)"
@upload_after_crop="trigger_upload=true"
@upload_after_crop="trigger_upload = true"
/>
<FileBrowser
ref="file_browser"
v-if="show_file_browser && !disable_file_browser"
@hide-browser="show_file_browser = false"
/>
<WebLink
ref="web_link"
v-if="show_web_link"
@hide-web-link="show_web_link = false"
/>
<WebLink ref="web_link" v-if="show_web_link" @hide-web-link="show_web_link = false" />
</div>
</template>
<script setup>
import { computed, ref, watch } from 'vue';
import FilePreview from './FilePreview.vue';
import FileBrowser from './FileBrowser.vue';
import WebLink from './WebLink.vue';
import GoogleDrivePicker from '../../integrations/google_drive_picker';
import ImageCropper from './ImageCropper.vue';
import { computed, ref, watch } from "vue";
import FilePreview from "./FilePreview.vue";
import FileBrowser from "./FileBrowser.vue";
import WebLink from "./WebLink.vue";
import GoogleDrivePicker from "../../integrations/google_drive_picker";
import ImageCropper from "./ImageCropper.vue";
// props
const props = defineProps({
show_upload_button: {
default: true
default: true,
},
disable_file_browser: {
default: false
default: false,
},
allow_multiple: {
default: true
default: true,
},
as_dataurl: {
default: false
default: false,
},
doctype: {
default: null
default: null,
},
docname: {
default: null
default: null,
},
fieldname: {
default: null
default: null,
},
folder: {
default: 'Home'
default: "Home",
},
method: {
default: null
default: null,
},
on_success: {
default: null
default: null,
},
make_attachments_public: {
default: null,
@ -169,15 +265,15 @@ const props = defineProps({
max_file_size: null, // 2048 -> 2KB
max_number_of_files: null,
allowed_file_types: [], // ['image/*', 'video/*', '.jpg', '.gif', '.pdf'],
crop_image_aspect_ratio: null // 1, 16 / 9, 4 / 3, NaN (free)
})
crop_image_aspect_ratio: null, // 1, 16 / 9, 4 / 3, NaN (free)
}),
},
attach_doc_image: {
default: false
default: false,
},
upload_notes: {
default: null // "Images or video, upto 2MB"
}
default: null, // "Images or video, upto 2MB"
},
});
// variables
@ -197,7 +293,7 @@ let hide_dialog_footer = ref(false);
let allow_take_photo = ref(false);
let allow_web_link = ref(true);
let google_drive_settings = ref({
enabled: false
enabled: false,
});
let wrapper_ready = ref(false);
@ -211,14 +307,13 @@ if (frappe.user_id !== "Guest") {
if (!resp.exc) {
google_drive_settings.value = resp.message;
}
}
},
});
}
if (props.restrictions.max_file_size == null) {
frappe.call('frappe.core.api.file.get_max_file_size')
.then(res => {
props.restrictions.max_file_size = Number(res.message);
});
frappe.call("frappe.core.api.file.get_max_file_size").then((res) => {
props.restrictions.max_file_size = Number(res.message);
});
}
if (props.restrictions.max_number_of_files == null && props.doctype) {
props.restrictions.max_number_of_files = frappe.get_meta(props.doctype)?.max_attachments;
@ -242,7 +337,7 @@ function on_file_input(e) {
add_files(file_input.value.files);
}
function remove_file(file) {
files.value = files.value.filter(f => f !== file);
files.value = files.value.filter((f) => f !== file);
}
function toggle_image_cropper(index) {
crop_image_with_index.value = show_image_cropper.value ? -1 : index;
@ -251,7 +346,7 @@ function toggle_image_cropper(index) {
}
function toggle_all_private() {
let flag;
let private_values = files.value.filter(file => file.private);
let private_values = files.value.filter((file) => file.private);
if (private_values.length < files.value.length) {
// there are some private and some public
// set all to private
@ -260,7 +355,7 @@ function toggle_all_private() {
// all are private, set all to public
flag = false;
}
files.value = files.value.map(file => {
files.value = files.value.map((file) => {
file.private = flag;
return file;
});
@ -268,12 +363,19 @@ function toggle_all_private() {
function show_max_files_number_warning(file) {
console.warn(
`File skipped because it exceeds the allowed specified limit of ${max_number_of_files} uploads`,
file,
file
);
if (props.doctype) {
MSG = __('File "{0}" was skipped because only {1} uploads are allowed for DocType "{2}"', [file.name, max_number_of_files, props.doctype])
MSG = __('File "{0}" was skipped because only {1} uploads are allowed for DocType "{2}"', [
file.name,
max_number_of_files,
props.doctype,
]);
} else {
MSG = __('File "{0}" was skipped because only {1} uploads are allowed', [file.name, max_number_of_files])
MSG = __('File "{0}" was skipped because only {1} uploads are allowed', [
file.name,
max_number_of_files,
]);
}
frappe.show_alert({
message: MSG,
@ -283,14 +385,14 @@ function show_max_files_number_warning(file) {
function add_files(file_array) {
let _files = Array.from(file_array)
.filter(check_restrictions)
.map(file => {
let is_image = file.type.startsWith('image');
.map((file) => {
let is_image = file.type.startsWith("image");
let size_kb = file.size / 1024;
return {
file_obj: file,
cropper_file: file,
crop_box_data: null,
optimize: size_kb > 200 && is_image && !file.type.includes('svg'),
optimize: size_kb > 200 && is_image && !file.type.includes("svg"),
name: file.name,
doc: null,
progress: 0,
@ -306,7 +408,7 @@ function add_files(file_array) {
// pop extra files as per FileUploader.restrictions.max_number_of_files
max_number_of_files = props.restrictions.max_number_of_files;
if (max_number_of_files && _files.length > max_number_of_files) {
_files.slice(max_number_of_files).forEach(file => {
_files.slice(max_number_of_files).forEach((file) => {
show_max_files_number_warning(file, props.doctype);
});
@ -315,8 +417,12 @@ function add_files(file_array) {
files.value = files.value.concat(_files);
// if only one file is allowed and crop_image_aspect_ratio is set, open cropper immediately
if (files.value.length === 1 && !props.allow_multiple && props.restrictions.crop_image_aspect_ratio != null) {
if (!files.value[0].file_obj.type.includes('svg')) {
if (
files.value.length === 1 &&
!props.allow_multiple &&
props.restrictions.crop_image_aspect_ratio != null
) {
if (!files.value[0].file_obj.type.includes("svg")) {
toggle_image_cropper(0);
}
}
@ -330,14 +436,14 @@ function check_restrictions(file) {
if (allowed_file_types && allowed_file_types.length) {
is_correct_type = allowed_file_types.some((type) => {
// is this is a mime-type
if (type.includes('/')) {
if (type.includes("/")) {
if (!file.type) return false;
return file.type.match(type);
}
// otherwise this is likely an extension
if (type[0] === '.') {
return file.name.endsWith(type);
if (type[0] === ".") {
return file.name.toLowerCase().endsWith(type.toLowerCase());
}
return false;
});
@ -348,17 +454,20 @@ function check_restrictions(file) {
}
if (!is_correct_type) {
console.warn('File skipped because of invalid file type', file);
console.warn("File skipped because of invalid file type", file);
frappe.show_alert({
message: __('File "{0}" was skipped because of invalid file type', [file.name]),
indicator: 'orange'
indicator: "orange",
});
}
if (!valid_file_size) {
console.warn('File skipped because of invalid file size', file.size, file);
console.warn("File skipped because of invalid file size", file.size, file);
frappe.show_alert({
message: __('File "{0}" was skipped because size exceeds {1} MB', [file.name, max_file_size / (1024 * 1024)]),
indicator: 'orange'
message: __('File "{0}" was skipped because size exceeds {1} MB', [
file.name,
max_file_size / (1024 * 1024),
]),
indicator: "orange",
});
}
@ -374,17 +483,12 @@ function upload_files() {
if (props.as_dataurl) {
return return_as_dataurl();
}
return frappe.run_serially(
files.value.map(
(file, i) =>
() => upload_file(file, i)
)
);
return frappe.run_serially(files.value.map((file, i) => () => upload_file(file, i)));
}
function upload_via_file_browser() {
let selected_file = file_browser.value.selected_node;
if (!selected_file.value) {
frappe.msgprint(__('Click on a file to select it.'));
frappe.msgprint(__("Click on a file to select it."));
close_dialog.value = true;
return Promise.reject();
}
@ -396,23 +500,22 @@ function upload_via_file_browser() {
function upload_via_web_link() {
let file_url = web_link.value.url;
if (!file_url) {
frappe.msgprint(__('Invalid URL'));
frappe.msgprint(__("Invalid URL"));
close_dialog.value = true;
return Promise.reject();
}
file_url = decodeURI(file_url)
file_url = decodeURI(file_url);
close_dialog.value = true;
return upload_file({
file_url
file_url,
});
}
function return_as_dataurl() {
let promises = files.value.map(file =>
frappe.dom.file_to_base64(file.file_obj)
.then(dataurl => {
file.dataurl = dataurl;
props.on_success && props.on_success(file);
})
let promises = files.value.map((file) =>
frappe.dom.file_to_base64(file.file_obj).then((dataurl) => {
file.dataurl = dataurl;
props.on_success && props.on_success(file);
})
);
close_dialog.value = true;
return Promise.all(promises);
@ -422,23 +525,23 @@ function upload_file(file, i) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.upload.addEventListener('loadstart', (e) => {
xhr.upload.addEventListener("loadstart", (e) => {
file.uploading = true;
})
xhr.upload.addEventListener('progress', (e) => {
});
xhr.upload.addEventListener("progress", (e) => {
if (e.lengthComputable) {
file.progress = e.loaded;
file.total = e.total;
}
})
xhr.upload.addEventListener('load', (e) => {
});
xhr.upload.addEventListener("load", (e) => {
file.uploading = false;
resolve();
})
xhr.addEventListener('error', (e) => {
});
xhr.addEventListener("error", (e) => {
file.failed = true;
reject();
})
});
xhr.onreadystatechange = () => {
if (xhr.readyState == XMLHttpRequest.DONE) {
if (xhr.status === 200) {
@ -447,10 +550,10 @@ function upload_file(file, i) {
let file_doc = null;
try {
r = JSON.parse(xhr.responseText);
if (r.message.doctype === 'File') {
if (r.message.doctype === "File") {
file_doc = r.message;
}
} catch(e) {
} catch (e) {
r = xhr.responseText;
}
@ -460,14 +563,16 @@ function upload_file(file, i) {
props.on_success(file_doc, r);
}
if (i == files.value.length - 1 && files.value.every(file => file.request_succeeded)) {
if (
i == files.value.length - 1 &&
files.value.every((file) => file.request_succeeded)
) {
close_dialog.value = true;
}
} else if (xhr.status === 403) {
file.failed = true;
let response = JSON.parse(xhr.responseText);
file.error_message = `Not permitted. ${response._error_message || ''}.`;
file.error_message = `Not permitted. ${response._error_message || ""}.`;
try {
// Append server messages which are useful hint for perm issues
@ -475,73 +580,73 @@ function upload_file(file, i) {
server_messages.forEach((m) => {
m = JSON.parse(m);
file.error_message += `\n ${m.message} `
})
file.error_message += `\n ${m.message} `;
});
} catch (e) {
console.warning("Failed to parse server message", e)
console.warning("Failed to parse server message", e);
}
} else if (xhr.status === 413) {
file.failed = true;
file.error_message = 'Size exceeds the maximum allowed file size.';
file.error_message = "Size exceeds the maximum allowed file size.";
} else {
file.failed = true;
file.error_message = xhr.status === 0 ? 'XMLHttpRequest Error' : `${xhr.status} : ${xhr.statusText}`;
file.error_message =
xhr.status === 0
? "XMLHttpRequest Error"
: `${xhr.status} : ${xhr.statusText}`;
let error = null;
try {
error = JSON.parse(xhr.responseText);
} catch(e) {
} catch (e) {
// pass
}
frappe.request.cleanup({}, error);
}
}
}
xhr.open('POST', '/api/method/upload_file', true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('X-Frappe-CSRF-Token', frappe.csrf_token);
};
xhr.open("POST", "/api/method/upload_file", true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("X-Frappe-CSRF-Token", frappe.csrf_token);
let form_data = new FormData();
if (file.file_obj) {
form_data.append('file', file.file_obj, file.name);
form_data.append("file", file.file_obj, file.name);
}
form_data.append('is_private', +file.private);
form_data.append('folder', props.folder);
form_data.append("is_private", +file.private);
form_data.append("folder", props.folder);
if (file.file_url) {
form_data.append('file_url', file.file_url);
form_data.append("file_url", file.file_url);
}
if (file.file_name) {
form_data.append('file_name', file.file_name);
form_data.append("file_name", file.file_name);
}
if (file.library_file_name) {
form_data.append('library_file_name', file.library_file_name);
form_data.append("library_file_name", file.library_file_name);
}
if (props.doctype && props.docname) {
form_data.append('doctype', props.doctype);
form_data.append('docname', props.docname);
form_data.append("doctype", props.doctype);
form_data.append("docname", props.docname);
}
if (props.fieldname) {
form_data.append('fieldname', props.fieldname);
form_data.append("fieldname", props.fieldname);
}
if (props.method) {
form_data.append('method', props.method);
form_data.append("method", props.method);
}
if (file.optimize) {
form_data.append('optimize', true);
form_data.append("optimize", true);
}
if (props.attach_doc_image) {
form_data.append('max_width', 200);
form_data.append('max_height', 200);
form_data.append("max_width", 200);
form_data.append("max_height", 200);
}
xhr.send(form_data);
@ -550,23 +655,23 @@ function upload_file(file, i) {
function capture_image() {
const capture = new frappe.ui.Capture({
animate: false,
error: true
error: true,
});
capture.show();
capture.submit(data_urls => {
data_urls.forEach(data_url => {
let filename = `capture_${frappe.datetime.now_datetime().replaceAll(/[: -]/g, '_')}.png`;
url_to_file(data_url, filename, 'image/png').then((file) =>
add_files([file])
);
capture.submit((data_urls) => {
data_urls.forEach((data_url) => {
let filename = `capture_${frappe.datetime
.now_datetime()
.replaceAll(/[: -]/g, "_")}.png`;
url_to_file(data_url, filename, "image/png").then((file) => add_files([file]));
});
});
}
function show_google_drive_picker() {
close_dialog.value = true;
let google_drive = new GoogleDrivePicker({
pickerCallback: data => google_drive_callback(data),
...google_drive_settings.value
pickerCallback: (data) => google_drive_callback(data),
...google_drive_settings.value,
});
google_drive.loadPicker();
}
@ -574,31 +679,36 @@ function google_drive_callback(data) {
if (data.action == google.picker.Action.PICKED) {
upload_file({
file_url: data.docs[0].url,
file_name: data.docs[0].name
file_name: data.docs[0].name,
});
} else if (data.action == google.picker.Action.CANCEL) {
cur_frm.attachments.new_attachment()
cur_frm.attachments.new_attachment();
}
}
function url_to_file(url, filename, mime_type) {
return fetch(url)
.then(res => res.arrayBuffer())
.then(buffer => new File([buffer], filename, { type: mime_type }));
.then((res) => res.arrayBuffer())
.then((buffer) => new File([buffer], filename, { type: mime_type }));
}
// computed
let upload_complete = computed(() => {
return files.value.length > 0
&& files.value.every(
file => file.total !== 0 && file.progress === file.total);
return (
files.value.length > 0 &&
files.value.every((file) => file.total !== 0 && file.progress === file.total)
);
});
// watcher
watch(files, (newvalue, oldvalue) => {
if (!props.allow_multiple && newvalue.length > 1) {
files.value = [newvalue[newvalue.length - 1]];
}
}, { deep: true });
watch(
files,
(newvalue, oldvalue) => {
if (!props.allow_multiple && newvalue.length > 1) {
files.value = [newvalue[newvalue.length - 1]];
}
},
{ deep: true }
);
defineExpose({
files,

View file

@ -13,7 +13,7 @@
:class="{
active: isNaN(aspect_ratio)
? isNaN(button.value)
: button.value === aspect_ratio
: button.value === aspect_ratio,
}"
:key="button.label"
@click="aspect_ratio = button.value"
@ -63,9 +63,9 @@ function crop_image() {
props.file.crop_box_data = cropper.value.getData();
const canvas = cropper.value.getCroppedCanvas();
const file_type = props.file.file_obj.type;
canvas.toBlob(blob => {
canvas.toBlob((blob) => {
var cropped_file_obj = new File([blob], props.file.name, {
type: blob.type
type: blob.type,
});
props.file.file_obj = cropped_file_obj;
emit("toggle_image_cropper");
@ -87,7 +87,7 @@ onMounted(() => {
scalable: false,
viewMode: 1,
data: crop_box,
aspectRatio: aspect_ratio.value
aspectRatio: aspect_ratio.value,
});
window.cropper = cropper.value;
};
@ -98,30 +98,33 @@ let aspect_ratio_buttons = computed(() => {
return [
{
label: __("1:1"),
value: 1
value: 1,
},
{
label: __("4:3"),
value: 4 / 3
value: 4 / 3,
},
{
label: __("16:9"),
value: 16 / 9
value: 16 / 9,
},
{
label: __("Free"),
value: NaN
}
value: NaN,
},
];
});
// watcher
watch(aspect_ratio, (value) => {
if (cropper.value) {
cropper.value.setAspectRatio(value);
}
}, { deep: true });
watch(
aspect_ratio,
(value) => {
if (cropper.value) {
cropper.value.setAspectRatio(value);
}
},
{ deep: true }
);
</script>
<style scoped>

View file

@ -4,7 +4,7 @@
:stroke-dasharray="circumference + ' ' + circumference"
:style="{
stroke: secondary,
strokeDashoffset: 0
strokeDashoffset: 0,
}"
:stroke-width="stroke"
fill="transparent"
@ -16,7 +16,7 @@
:stroke-dasharray="circumference + ' ' + circumference"
:style="{
stroke: primary,
strokeDashoffset: strokeDashoffset
strokeDashoffset: strokeDashoffset,
}"
:stroke-width="stroke"
fill="transparent"
@ -32,7 +32,7 @@
:style="{
color: 'var(--text-color)',
fontSize: 'var(--text-xs)',
fontWeight: 'var(--text-bold)'
fontWeight: 'var(--text-bold)',
}"
>
{{ progress }}%
@ -49,7 +49,7 @@ const props = defineProps({
secondary: String,
radius: Number,
progress: Number,
stroke: Number
stroke: Number,
});
// variables
@ -60,7 +60,6 @@ let circumference = ref(normalizedRadius.value * 2 * Math.PI);
let strokeDashoffset = computed(() => {
return circumference.value - (props.progress / 100) * circumference.value;
});
</script>
<style scoped>

View file

@ -1,9 +1,7 @@
<template>
<div class="file-web-link margin-bottom">
<a href class="text-muted text-medium"
@click.prevent="emit('hide-web-link')"
>
{{ __('← Back to upload files') }}
<a href class="text-muted text-medium" @click.prevent="emit('hide-web-link')">
{{ __("← Back to upload files") }}
</a>
<div class="input-group">
<input
@ -11,7 +9,7 @@
class="form-control"
:placeholder="__('Attach a web link')"
v-model="url"
>
/>
</div>
</div>
</template>

View file

@ -1520,9 +1520,8 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
if (this.filter_area.is_being_edited()) {
return true;
}
// this is set when a bulk operation is called from a list view which might update the list view
// this is to avoid the list view from refreshing a lot of times
// the list view is updated once after the bulk operation is complete
// this flag is left for backward compatibility, there's no need to prevent realtime
// refresh. They are by default debounced now and there's no way to bypass that.
if (this.disable_list_update) {
return true;
}
@ -1724,7 +1723,6 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
get_workflow_action_menu_items() {
const workflow_actions = [];
const me = this;
if (frappe.model.has_workflow(this.doctype)) {
const actions = frappe.workflow.get_all_transition_actions(this.doctype);
@ -1733,16 +1731,11 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
label: __(action),
name: action,
action: () => {
me.disable_list_update = true;
frappe
.xcall("frappe.model.workflow.bulk_workflow_approval", {
docnames: this.get_checked_items(true),
doctype: this.doctype,
action: action,
})
.finally(() => {
me.disable_list_update = false;
});
frappe.xcall("frappe.model.workflow.bulk_workflow_approval", {
docnames: this.get_checked_items(true),
doctype: this.doctype,
action: action,
});
},
is_workflow_action: true,
});
@ -1803,9 +1796,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return {
label: __("Assign To", null, "Button in list view actions menu"),
action: () => {
this.disable_list_update = true;
bulk_operations.assign(this.get_checked_items(true), () => {
this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@ -1818,9 +1809,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return {
label: __("Apply Assignment Rule", null, "Button in list view actions menu"),
action: () => {
this.disable_list_update = true;
bulk_operations.apply_assignment_rule(this.get_checked_items(true), () => {
this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@ -1833,9 +1822,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return {
label: __("Add Tags", null, "Button in list view actions menu"),
action: () => {
this.disable_list_update = true;
bulk_operations.add_tags(this.get_checked_items(true), () => {
this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@ -1872,9 +1859,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
);
}
frappe.confirm(message, () => {
this.disable_list_update = true;
bulk_operations.delete(docnames, () => {
this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@ -1897,9 +1882,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
"Title of confirmation dialog"
),
() => {
this.disable_list_update = true;
bulk_operations.submit_or_cancel(docnames, "cancel", () => {
this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@ -1924,9 +1907,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
"Title of confirmation dialog"
),
() => {
this.disable_list_update = true;
bulk_operations.submit_or_cancel(docnames, "submit", () => {
this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@ -1950,9 +1931,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
}
});
this.disable_list_update = true;
bulk_operations.edit(this.get_checked_items(true), field_mappings, () => {
this.disable_list_update = false;
this.refresh();
});
},

View file

@ -346,7 +346,7 @@ frappe.views.Workspace = class Workspace {
) {
default_page = {
name: localStorage.current_page,
public: localStorage.is_current_page_public == "true",
public: localStorage.is_current_page_public != "false",
};
} else if (Object.keys(this.all_pages).length !== 0) {
default_page = { name: this.all_pages[0].title, public: this.all_pages[0].public };

View file

@ -19,10 +19,7 @@
handle=".icon-drag"
>
<template #item="{ element }">
<div
class="mt-2 row align-center column-row"
v-for="column in df.table_columns"
>
<div class="mt-2 row align-center column-row" v-for="column in df.table_columns">
<div class="col-8">
<div class="column-label d-flex align-center">
<div class="px-2 icon-drag ml-n2">
@ -50,10 +47,7 @@
max="100"
step="5"
/>
<button
class="ml-2 btn btn-xs btn-icon"
@click="remove_column(column)"
>
<button class="ml-2 btn btn-xs btn-icon" @click="remove_column(column)">
<svg class="icon icon-sm">
<use href="#icon-close"></use>
</svg>
@ -74,7 +68,7 @@ const props = defineProps(["df"]);
// methods
function remove_column(column) {
props.df["table_columns"] = props.df.table_columns.filter(_column => _column !== column)
props.df["table_columns"] = props.df.table_columns.filter((_column) => _column !== column);
}
// computed
let help_message = computed(() => {

View file

@ -7,10 +7,7 @@
v-if="df.fieldtype == 'HTML' && df.html"
v-html="df.html"
></div>
<div
class="custom-html"
v-if="df.fieldtype == 'Field Template'"
>
<div class="custom-html" v-if="df.fieldtype == 'Field Template'">
{{ df.label }}
</div>
<input
@ -24,9 +21,7 @@
@blur="editing = false"
/>
<span v-else-if="df.label">{{ df.label }}</span>
<i class="text-muted" v-else>
{{ __("No Label") }} ({{ df.fieldname }})
</i>
<i class="text-muted" v-else> {{ __("No Label") }} ({{ df.fieldname }}) </i>
</div>
<div class="field-actions">
<button
@ -45,10 +40,7 @@
>
Configure columns
</button>
<button
class="btn btn-xs btn-icon"
@click="df['remove'] = true"
>
<button class="btn btn-xs btn-icon" @click="df['remove'] = true">
<svg class="icon icon-sm">
<use href="#icon-close"></use>
</svg>
@ -94,14 +86,14 @@ function edit_html() {
label: __("HTML"),
fieldname: "html",
fieldtype: "Code",
options: "HTML"
}
options: "HTML",
},
],
primary_action: ({ html }) => {
html = frappe.dom.remove_script_and_style(html);
props.df["html"] = html;
d.hide();
}
},
});
d.set_value("html", props.df.html);
d.show();
@ -112,7 +104,7 @@ function configure_columns() {
fields: [
{
fieldtype: "HTML",
fieldname: "columns_area"
fieldname: "columns_area",
},
{
label: "",
@ -130,8 +122,8 @@ function configure_columns() {
dialog.set_value("add_column", "");
}
}
}
}
},
},
],
on_page_show: () => {
createApp(ConfigureColumnsVue, { df: props.df }).mount(
@ -139,8 +131,8 @@ function configure_columns() {
);
},
on_hide: () => {
props.df["table_columns"] = props.df.table_columns.filter(col => !col.invalid_width);
}
props.df["table_columns"] = props.df.table_columns.filter((col) => !col.invalid_width);
},
});
dialog.show();
}
@ -149,18 +141,18 @@ function get_all_columns() {
let more_columns = [
{
label: __("Sr No."),
value: "idx"
}
value: "idx",
},
];
return more_columns.concat(
meta.fields
.map(tf => {
.map((tf) => {
if (frappe.model.no_value_type.includes(tf.fieldtype)) {
return;
}
return {
label: tf.label,
value: tf.fieldname
value: tf.fieldname,
};
})
.filter(Boolean)
@ -172,8 +164,8 @@ function get_column_to_add(fieldname) {
label: __("Sr No."),
fieldtype: "Data",
fieldname: "idx",
width: 10
}
width: 10,
},
};
if (fieldname in standard_columns) {
@ -182,7 +174,7 @@ function get_column_to_add(fieldname) {
return {
...frappe.meta.get_docfield(props.df.options, fieldname),
width: 10
width: 10,
};
}
function validate_table_columns() {
@ -214,7 +206,6 @@ watch(
() => validate_table_columns(),
{ deep: true }
);
</script>
<style scoped>

View file

@ -1,10 +1,7 @@
<template>
<div class="html-editor">
<div class="d-flex justify-content-end">
<button
class="btn btn-default btn-xs btn-edit"
@click="toggle_edit"
>
<button class="btn btn-default btn-xs btn-edit" @click="toggle_edit">
{{ !editing ? buttonLabel : __("Done") }}
</button>
</div>
@ -46,9 +43,9 @@ function toggle_edit() {
max_lines: 30,
change: () => {
emit("change", get_value());
}
},
},
render_input: true
render_input: true,
});
}
control.value.set_value(props.value);

View file

@ -13,11 +13,7 @@
type="button"
class="btn btn-xs"
@click="letterhead.align = direction"
:class="
letterhead.align == direction
? 'btn-secondary'
: 'btn-default'
"
:class="letterhead.align == direction ? 'btn-secondary' : 'btn-default'"
>
{{ direction }}
</button>
@ -30,12 +26,7 @@
min="20"
:max="range_input_field === 'image_width' ? 700 : 500"
:value="letterhead[range_input_field]"
@input="
e =>
(letterhead[range_input_field] = parseFloat(
e.target.value
))
"
@input="(e) => (letterhead[range_input_field] = parseFloat(e.target.value))"
/>
</div>
<div>
@ -58,11 +49,7 @@
class="ml-2 btn btn-default btn-xs btn-edit"
@click="toggle_edit_letterhead"
>
{{
!store.edit_letterhead
? __("Edit Letter Head")
: __("Done")
}}
{{ !store.edit_letterhead ? __("Edit Letter Head") : __("Done") }}
</button>
<button
v-if="!letterhead"
@ -73,10 +60,7 @@
</button>
</div>
</div>
<div
v-if="letterhead && !store.edit_letterhead"
v-html="letterhead.content"
></div>
<div v-if="letterhead && !store.edit_letterhead" v-html="letterhead.content"></div>
<!-- <div v-show="letterhead && store.edit_letterhead" ref="editor"></div> -->
<div
class="edit-letterhead"
@ -85,8 +69,8 @@
justifyContent: {
Left: 'flex-start',
Center: 'center',
Right: 'flex-end'
}[letterhead.align]
Right: 'flex-end',
}[letterhead.align],
}"
>
<div class="edit-image">
@ -101,7 +85,7 @@
height:
range_input_field === 'image_height'
? letterhead.image_height + 'px'
: null
: null,
}"
/>
</div>
@ -143,15 +127,15 @@ function toggle_edit_letterhead() {
change: () => {
letterhead.value._dirty = true;
letterhead.value.content = control.value.get_value();
}
},
},
render_input: true,
only_input: true,
no_wrapper: true
no_wrapper: true,
});
}
control.value.set_value(letterhead.value.content);
};
}
function change_letterhead() {
let d = new frappe.ui.Dialog({
title: __("Change Letter Head"),
@ -160,62 +144,52 @@ function change_letterhead() {
label: __("Letter Head"),
fieldname: "letterhead",
fieldtype: "Link",
options: "Letter Head"
}
options: "Letter Head",
},
],
primary_action: ({ letterhead }) => {
if (letterhead) {
set_letterhead(letterhead);
}
d.hide();
}
},
});
d.show();
};
}
function upload_image() {
new frappe.ui.FileUploader({
folder: "Home/Attachments",
on_success: file_doc => {
get_image_dimensions(file_doc.file_url).then(
({ width, height }) => {
letterhead.value["image"] = file_doc.file_url;
let new_width = width;
let new_height = height;
aspect_ratio.value = width / height;
range_input_field.value =
aspect_ratio.value > 1
? "image_width"
: "image_height";
on_success: (file_doc) => {
get_image_dimensions(file_doc.file_url).then(({ width, height }) => {
letterhead.value["image"] = file_doc.file_url;
let new_width = width;
let new_height = height;
aspect_ratio.value = width / height;
range_input_field.value = aspect_ratio.value > 1 ? "image_width" : "image_height";
if (width > 200) {
new_width = 200;
new_height = new_width / aspect_ratio.value;
}
if (height > 80) {
new_height = 80;
new_width = aspect_ratio.value * new_height;
}
letterhead.value["image_height"] = new_height;
letterhead.value["image_width"] = new_width;
if (width > 200) {
new_width = 200;
new_height = new_width / aspect_ratio.value;
}
);
}
if (height > 80) {
new_height = 80;
new_width = aspect_ratio.value * new_height;
}
letterhead.value["image_height"] = new_height;
letterhead.value["image_width"] = new_width;
});
},
});
};
}
function set_letterhead(_letterhead) {
store.value.change_letterhead(_letterhead).then(() => {
get_image_dimensions(letterhead.value.image).then(
({ width, height }) => {
aspect_ratio.value = width / height;
range_input_field.value =
aspect_ratio.value > 1
? "image_width"
: "image_height";
}
);
get_image_dimensions(letterhead.value.image).then(({ width, height }) => {
aspect_ratio.value = width / height;
range_input_field.value = aspect_ratio.value > 1 ? "image_width" : "image_height";
});
});
};
}
function create_letterhead() {
let d = new frappe.ui.Dialog({
title: __("Create Letter Head"),
@ -223,23 +197,23 @@ function create_letterhead() {
{
label: __("Letter Head Name"),
fieldname: "name",
fieldtype: "Data"
}
fieldtype: "Data",
},
],
primary_action: ({ name }) => {
return frappe.db
.insert({
doctype: "Letter Head",
letter_head_name: name,
source: "Image"
source: "Image",
})
.then(doc => {
.then((doc) => {
d.hide();
store.value.change_letterhead(doc.name).then(() => {
toggle_edit_letterhead();
});
});
}
},
});
d.show();
}
@ -249,34 +223,33 @@ onMounted(() => {
set_letterhead(frappe.boot.sysdefaults.letter_head);
}
watch(() => {
return letterhead.value
? letterhead.value[range_input_field.value]
: null;
}, () => {
if (aspect_ratio.value === null) return;
watch(
() => {
return letterhead.value ? letterhead.value[range_input_field.value] : null;
},
() => {
if (aspect_ratio.value === null) return;
let update_field =
range_input_field.value == "image_width"
? "image_height"
: "image_width";
letterhead.value[update_field] =
update_field == "image_width"
? aspect_ratio.value * letterhead.value.image_height
: letterhead.value.image_width / aspect_ratio.value;
});
let update_field =
range_input_field.value == "image_width" ? "image_height" : "image_width";
letterhead.value[update_field] =
update_field == "image_width"
? aspect_ratio.value * letterhead.value.image_height
: letterhead.value.image_width / aspect_ratio.value;
}
);
});
// watch
watch(letterhead, () => {
if (!letterhead.value) return;
if (letterhead.value.image_width && letterhead.value.image_height) {
let dimension =
letterhead.value.image_width > letterhead.value.image_height
? "width"
: "height";
let dimension_value = letterhead.value["image_" + dimension];
letterhead.value.content = `
watch(
letterhead,
() => {
if (!letterhead.value) return;
if (letterhead.value.image_width && letterhead.value.image_height) {
let dimension =
letterhead.value.image_width > letterhead.value.image_height ? "width" : "height";
let dimension_value = letterhead.value["image_" + dimension];
letterhead.value.content = `
<div style="text-align: ${letterhead.value.align.toLowerCase()};">
<img
src="${letterhead.value.image}"
@ -285,8 +258,11 @@ watch(letterhead, () => {
style="${dimension}: ${dimension_value}px;">
</div>
`;
}
}, { deep: true }, { immediate: true });
}
},
{ deep: true },
{ immediate: true }
);
</script>
<style scoped>

View file

@ -59,7 +59,7 @@ function refresh() {
iframe.value?.contentWindow.location.reload();
}
function get_default_docname() {
return frappe.db.get_list(doctype.value, { limit: 1 }).then(doc => {
return frappe.db.get_list(doctype.value, { limit: 1 }).then((doc) => {
return doc.length > 0 ? doc[0].name : null;
});
}
@ -78,9 +78,7 @@ let url = computed(() => {
params.append("letterhead", store.value.letterhead.name);
}
let _url =
type.value == "PDF"
? `/api/method/frappe.utils.weasyprint.download_pdf`
: "/printpreview";
type.value == "PDF" ? `/api/method/frappe.utils.weasyprint.download_pdf` : "/printpreview";
return `${_url}?${params.toString()}`;
});
@ -95,9 +93,9 @@ onMounted(() => {
options: doctype.value,
change: () => {
docname.value = doc_select.value.get_value();
}
},
},
render_input: true
render_input: true,
});
preview_type.value = frappe.ui.form.make_control({
parent: preview_type_ref.value,
@ -108,12 +106,12 @@ onMounted(() => {
options: ["PDF", "HTML"],
change: () => {
type.value = preview_type.value.get_value();
}
},
},
render_input: true
render_input: true,
});
preview_type.value.set_value(type.value);
get_default_docname().then(doc_name => {
get_default_docname().then((doc_name) => {
doc_name && doc_select.value.set_value(doc_name);
});
});

View file

@ -57,8 +57,8 @@ function add_section_above(section) {
label: "",
columns: [
{ label: "", fields: [] },
{ label: "", fields: [] }
]
{ label: "", fields: [] },
],
});
}
sections.push(_section);
@ -75,12 +75,12 @@ let rootStyles = computed(() => {
margin_top = 0,
margin_bottom = 0,
margin_left = 0,
margin_right = 0
margin_right = 0,
} = print_format.value;
return {
padding: `${margin_top}mm ${margin_right}mm ${margin_bottom}mm ${margin_left}mm`,
width: "210mm",
minHeight: "297mm"
minHeight: "297mm",
};
});
let page_number_style = computed(() => {
@ -89,7 +89,7 @@ let page_number_style = computed(() => {
background: "white",
padding: "4px",
borderRadius: "var(--border-radius)",
border: "1px solid var(--border-color)"
border: "1px solid var(--border-color)",
};
if (print_format.value.page_number.includes("Top")) {
style.top = print_format.value.margin_top / 2 + "mm";

View file

@ -27,14 +27,12 @@ let show_preview = ref(false);
// computed
let $store = computed(() => {
return getStore(props.print_format_name)
return getStore(props.print_format_name);
});
let shouldRender = computed(() => {
return Boolean(
$store.value.print_format.value &&
$store.value.meta.value &&
$store.value.layout.value
$store.value.print_format.value && $store.value.meta.value && $store.value.layout.value
);
});

View file

@ -4,11 +4,7 @@
<div class="sidebar-menu">
<div class="sidebar-label">{{ __("Page Margins") }}</div>
<div class="margin-controls">
<div
class="form-group"
v-for="df in margins"
:key="df.fieldname"
>
<div class="form-group" v-for="df in margins" :key="df.fieldname">
<div class="clearfix">
<label class="control-label">
{{ df.label }}
@ -21,13 +17,7 @@
class="form-control form-control-sm"
:value="print_format[df.fieldname]"
min="0"
@change="
e =>
update_margin(
df.fieldname,
e.target.value
)
"
@change="(e) => update_margin(df.fieldname, e.target.value)"
/>
</div>
</div>
@ -43,10 +33,7 @@
class="form-control form-control-sm"
v-model="print_format.font"
>
<option
v-for="font in google_fonts"
:value="font"
>
<option v-for="font in google_fonts" :value="font">
{{ font }}
</option>
</select>
@ -65,10 +52,7 @@
placeholder="12, 13, 14"
:value="print_format.font_size"
@change="
e =>
(print_format.font_size = parseFloat(
e.target.value
))
(e) => (print_format.font_size = parseFloat(e.target.value))
"
/>
</div>
@ -112,10 +96,7 @@
item-key="id"
>
<template #item="{ element }">
<div
class="field"
:title="element.fieldname"
>
<div class="field" :title="element.fieldname">
{{ element.label }}
</div>
</template>
@ -157,7 +138,7 @@ function clone_field(df) {
"options",
"table_columns",
"html",
"field_template"
"field_template",
]);
if (cloned.custom) {
// generate unique fieldnames for custom blocks
@ -171,16 +152,14 @@ let margins = computed(() => {
return [
{ label: __("Top"), fieldname: "margin_top" },
{ label: __("Bottom"), fieldname: "margin_bottom" },
{ label: __("Left", null, 'alignment'), fieldname: "margin_left" },
{ label: __("Right", null, 'alignment'), fieldname: "margin_right" }
{ label: __("Left", null, "alignment"), fieldname: "margin_left" },
{ label: __("Right", null, "alignment"), fieldname: "margin_right" },
];
});
let fields = computed(() => {
let fields = meta.value.fields
.filter(df => {
if (
["Section Break", "Column Break"].includes(df.fieldtype)
) {
.filter((df) => {
if (["Section Break", "Column Break"].includes(df.fieldtype)) {
return false;
}
if (search_text.value) {
@ -195,12 +174,12 @@ let fields = computed(() => {
return true;
}
})
.map(df => {
.map((df) => {
let out = {
label: df.label,
fieldname: df.fieldname,
fieldtype: df.fieldtype,
options: df.options
options: df.options,
};
if (df.fieldtype == "Table") {
out.table_columns = get_table_columns(df);
@ -214,27 +193,27 @@ let fields = computed(() => {
fieldname: "custom_html",
fieldtype: "HTML",
html: "",
custom: 1
custom: 1,
},
{
label: __("ID (name)"),
fieldname: "name",
fieldtype: "Data"
fieldtype: "Data",
},
{
label: __("Spacer"),
fieldname: "spacer",
fieldtype: "Spacer",
custom: 1
custom: 1,
},
{
label: __("Divider"),
fieldname: "divider",
fieldtype: "Divider",
custom: 1
custom: 1,
},
...print_templates.value,
...fields
...fields,
];
});
let print_templates = computed(() => {
@ -243,21 +222,18 @@ let print_templates = computed(() => {
for (let template of templates) {
let df;
if (template.field) {
df = frappe.meta.get_docfield(
meta.value.name,
template.field
);
df = frappe.meta.get_docfield(meta.value.name, template.field);
} else {
df = {
label: template.name,
fieldname: frappe.scrub(template.name)
fieldname: frappe.scrub(template.name),
};
}
out.push({
label: `${__(df.label)} (${__("Field Template")})`,
fieldname: df.fieldname + "_template",
fieldtype: "Field Template",
field_template: template.name
field_template: template.name,
});
}
return out;
@ -270,7 +246,7 @@ let page_number_positions = computed(() => {
{ label: __("Top Right"), value: "Top Right" },
{ label: __("Bottom Left"), value: "Bottom Left" },
{ label: __("Bottom Center"), value: "Bottom Center" },
{ label: __("Bottom Right"), value: "Bottom Right" }
{ label: __("Bottom Right"), value: "Bottom Right" },
];
});
@ -278,7 +254,7 @@ let page_number_positions = computed(() => {
onMounted(() => {
let method =
"frappe.printing.page.print_format_builder_beta.print_format_builder_beta.get_google_fonts";
frappe.call(method).then(r => {
frappe.call(method).then((r) => {
google_fonts.value = r.message || [];
if (!google_fonts.value.includes(print_format.value.font)) {
google_fonts.value.push(print_format.value.font);

View file

@ -28,10 +28,7 @@
<use href="#icon-dot-horizontal"></use>
</svg>
</button>
<div
class="dropdown-menu dropdown-menu-right"
role="menu"
>
<div class="dropdown-menu dropdown-menu-right" role="menu">
<button
v-for="option in section_options"
class="dropdown-item"
@ -44,17 +41,11 @@
</div>
</div>
<div class="row section-columns">
<div
class="column col"
v-for="(column, i) in section.columns"
:key="i"
>
<div class="column col" v-for="(column, i) in section.columns" :key="i">
<draggable
class="drag-container"
:style="{
backgroundColor: column.fields.length
? null
: 'var(--gray-50)'
backgroundColor: column.fields.length ? null : 'var(--gray-50)',
}"
v-model="column.fields"
group="fields"
@ -68,10 +59,7 @@
</div>
</div>
</div>
<div
class="my-4 text-center text-muted font-italic"
v-if="section.page_break"
>
<div class="my-4 text-center text-muted font-italic" v-if="section.page_break">
{{ __("Page Break") }}
</div>
</div>
@ -93,7 +81,7 @@ function add_column() {
if (props.section.columns.length < 4) {
props.section.columns.push({
label: "",
fields: []
fields: [],
});
}
}
@ -121,46 +109,50 @@ let section_options = computed(() => {
return [
{
label: __("Add section above"),
action: () => emit("add_section_above")
action: () => emit("add_section_above"),
},
{
label: __("Add column"),
action: add_column,
condition: () => props.section.columns.length < 4
condition: () => props.section.columns.length < 4,
},
{
label: __("Remove column"),
action: remove_column,
condition: () => props.section.columns.length > 1
condition: () => props.section.columns.length > 1,
},
{
label: __("Add page break"),
action: add_page_break,
condition: () => !props.section.page_break
condition: () => !props.section.page_break,
},
{
label: __("Remove page break"),
action: remove_page_break,
condition: () => props.section.page_break
condition: () => props.section.page_break,
},
{
label: __("Remove section"),
action: () => { props.section["remove"] = true }
action: () => {
props.section["remove"] = true;
},
},
{
label: __("Field Orientation (Left-Right)"),
condition: () => !props.section.field_orientation,
action: () => { props.section["field_orientation"] = "left-right" }
action: () => {
props.section["field_orientation"] = "left-right";
},
},
{
label: __("Field Orientation (Top-Down)"),
condition: () =>
props.section.field_orientation == "left-right",
action: () => { props.section["field_orientation"] = "" }
}
].filter(option => (option.condition ? option.condition() : true));
})
condition: () => props.section.field_orientation == "left-right",
action: () => {
props.section["field_orientation"] = "";
},
},
].filter((option) => (option.condition ? option.condition() : true));
});
</script>
<style scoped>

View file

@ -6,8 +6,8 @@ import { useStore } from "../store";
const props = defineProps({
node: {
type: Object,
required: true
}
required: true,
},
});
const isValidConnection = ({ source, target }) => {
@ -26,21 +26,25 @@ let store = useStore();
const { edges, findNode } = useVueFlow();
watch(
() => findNode(props.node.id)?.selected,
val => {
(val) => {
if (val) store.workflow.selected = props.node;
let connected_edges = edges.value.filter(
edge => edge.source === props.node.id || edge.target === props.node.id
(edge) => edge.source === props.node.id || edge.target === props.node.id
);
connected_edges.forEach(edge => edge.selected = val);
connected_edges.forEach((edge) => (edge.selected = val));
}
);
let label = computed(() => findNode(props.node.id)?.data?.action);
watch(() => props.node.data, () => {
store.ref_history.commit();
}, { deep: true });
watch(
() => props.node.data,
() => {
store.ref_history.commit();
},
{ deep: true }
);
</script>
<template>

View file

@ -11,21 +11,21 @@ const props = defineProps({
targetPosition: { type: String, required: false },
sourceHandle: { type: Object, required: false },
targetHandle: { type: Object, required: false },
markerEnd: { type: String, required: false }
markerEnd: { type: String, required: false },
});
let opposite = {
left: "left",
right: "right",
top: "bottom",
bottom: "top"
bottom: "top",
};
const d = computed(() =>
getSmoothStepPath({
...props,
borderRadius: 30,
targetPosition: opposite[props.targetPosition]
targetPosition: opposite[props.targetPosition],
})
);
</script>

View file

@ -9,4 +9,4 @@ $alert-types: info, success, warning, danger;
border: none;
}
}
}
}

View file

@ -8,15 +8,15 @@
clip: rect(0, 0, 0, 0);
}
&> input {
& > input {
display: block;
}
&> ul:empty {
& > ul:empty {
display: none;
}
&> ul {
& > ul {
position: absolute;
width: 100%;
list-style: none;
@ -33,7 +33,7 @@
z-index: 4;
min-width: 250px;
&> li {
& > li {
cursor: pointer;
@include get_textstyle("sm", "regular");
padding: var(--padding-sm);
@ -54,12 +54,13 @@
}
}
&> li .link-option {
& > li .link-option {
font-weight: normal;
color: var(--text-color);
}
&> li:hover, &> li[aria-selected=true] {
& > li:hover,
& > li[aria-selected="true"] {
background-color: var(--awesomplete-hover-bg);
color: var(--text-color);
}
@ -68,4 +69,4 @@
text-decoration: none;
}
}
}
}

View file

@ -24,7 +24,8 @@
height: var(--btn-height);
padding: 0px;
@extend .center-content;
&.btn-default, &.btn-secondary {
&.btn-default,
&.btn-secondary {
min-width: 28px;
}
}
@ -41,7 +42,9 @@
);
color: $white;
&:hover, &:active, &:focus {
&:hover,
&:active,
&:focus {
color: $white;
}
.icon {
@ -61,7 +64,8 @@
);
color: var(--primary);
&:hover, &:active {
&:hover,
&:active {
color: var(--primary);
}
@ -73,7 +77,8 @@
.btn.btn-secondary {
background-color: var(--control-bg);
color: var(--text-color);
&:hover, &:active {
&:hover,
&:active {
background-color: var(--btn-default-hover-bg);
color: var(--text-color);
}
@ -82,7 +87,8 @@
.btn.btn-default {
background-color: var(--control-bg);
color: var(--text-color);
&:hover, &:active {
&:hover,
&:active {
background: var(--btn-default-hover-bg);
color: var(--text-color);
}
@ -120,7 +126,7 @@
box-shadow: none;
}
.btn-primary:active {
color: var(--gray-900) !important;
background-color: var(--invert-neutral) !important;
color: var(--gray-900) !important;
background-color: var(--invert-neutral) !important;
}
}

View file

@ -19,7 +19,8 @@
cursor: pointer;
}
.color-selector, .hue-selector {
.color-selector,
.hue-selector {
width: 12px;
height: 12px;
background: transparent;
@ -27,11 +28,12 @@
border-radius: 50%;
/* box-shadow: 0 0 0 1px gray, 0 0 0 3px white, 0 0 0 4px gray; */
border: 1px solid rgba(0, 0, 0, 0.2);
&::before, &::after {
&::before,
&::after {
position: absolute;
background-color: transparent;
border: 1px solid rgba(0, 0, 0, 0.2);
content: ' ';
content: " ";
border-radius: 50%;
}
@ -74,8 +76,8 @@
position: relative;
background: linear-gradient(
90deg,
hsl(0, 100%, 50%),
hsl(60, 100%, 50%),
hsl(0, 100%, 50%),
hsl(60, 100%, 50%),
hsl(120, 100%, 50%),
hsl(180, 100%, 50%),
hsl(240, 100%, 50%),
@ -92,7 +94,7 @@
}
}
.frappe-control[data-fieldtype='Color'] {
.frappe-control[data-fieldtype="Color"] {
input {
padding-left: 38px;
}
@ -108,9 +110,9 @@
position: absolute;
top: 5px;
left: 8px;
content: ' ';
content: " ";
&.no-value {
background: url('/assets/frappe/images/color-circle.png');
background: url("/assets/frappe/images/color-circle.png");
background-size: contain;
}
}

View file

@ -125,7 +125,8 @@ select.form-control {
}
}
.selectable-item:hover, .selectable-item.highlighted {
.selectable-item:hover,
.selectable-item.highlighted {
background-color: var(--fg-hover-color);
}
@ -142,7 +143,7 @@ select.form-control {
.frappe-control {
@include get_textstyle("base", "regular");
.control-label.reqd:after {
content: ' *';
content: " *";
color: var(--red-400);
}
.help:empty {
@ -193,7 +194,7 @@ select.form-control {
}
}
.frappe-control:not([data-fieldtype='MultiSelectPills']):not([data-fieldtype='Table MultiSelect']) {
.frappe-control:not([data-fieldtype="MultiSelectPills"]):not([data-fieldtype="Table MultiSelect"]) {
&.has-error {
input {
border: 1px solid var(--error-border);
@ -205,8 +206,8 @@ select.form-control {
}
}
.frappe-control[data-fieldtype='MultiSelectPills'],
.frappe-control[data-fieldtype='Table MultiSelect'] {
.frappe-control[data-fieldtype="MultiSelectPills"],
.frappe-control[data-fieldtype="Table MultiSelect"] {
&.has-error {
.control-input {
border: 1px solid var(--error-border);
@ -257,7 +258,8 @@ select.form-control {
}
/* progress bar */
.progress, .progress-bar {
.progress,
.progress-bar {
box-shadow: none;
}
@ -361,7 +363,8 @@ textarea.form-control {
overflow-wrap: break-word;
}
.frappe-control[data-fieldtype="Data"] .control-input, .control-value {
.frappe-control[data-fieldtype="Data"] .control-input,
.control-value {
position: relative;
}
@ -372,26 +375,30 @@ textarea.form-control {
padding: 3px;
}
.markdown-preview, .html-preview {
.markdown-preview,
.html-preview {
padding: var(--padding-md);
min-height: 300px;
max-height: 600px;
overflow: auto;
}
.markdown-toggle, .html-toggle {
.markdown-toggle,
.html-toggle {
margin-bottom: var(--margin-xs);
}
.barcode-scanner {
position: relative;
& > canvas, & > video {
& > canvas,
& > video {
max-width: 100%;
width: 100%;
}
canvas.drawing, canvas.drawingBuffer {
canvas.drawing,
canvas.drawingBuffer {
position: absolute;
left: 0;
top: 0;

View file

@ -19,12 +19,10 @@ $disabled-input-height: 22px;
--margin-xl: 30px;
--margin-2xl: 40px;
--modal-shadow: var(--shadow-md);
--card-shadow: var(--shadow-sm);
--btn-shadow: var(--shadow-xs);
// navbar
--navbar-height: 48px;
@ -50,8 +48,6 @@ $disabled-input-height: 22px;
--bg-pink: var(--pink-50);
--bg-cyan: var(--cyan-50);
--text-on-blue: var(--blue-700);
--text-on-light-blue: var(--blue-600);
--text-on-dark-blue: var(--blue-800);
@ -102,6 +98,9 @@ $disabled-input-height: 22px;
--btn-default-bg: var(--gray-100);
--btn-default-hover-bg: var(--gray-300);
// Border Colors
--border-primary: var(--gray-900);
// Other Colors
--sidebar-select-color: var(--gray-200);
@ -125,7 +124,6 @@ $disabled-input-height: 22px;
--code-block-bg: var(--gray-900);
--code-block-text: var(--gray-400);
--primary-color: var(--gray-900);
--btn-height: 28px;
@ -140,8 +138,11 @@ $disabled-input-height: 22px;
--checkbox-focus-shadow: 0 0 0 2px var(--gray-300);
--checkbox-gradient: linear-gradient(180deg, var(--primary) -124.51%, var(--primary) 100%);
--checkbox-disabled-gradient: linear-gradient(180deg, var(--disabled-control-bg) -124.51%, var(--disabled-control-bg) 100%);
--checkbox-disabled-gradient: linear-gradient(
180deg,
var(--disabled-control-bg) -124.51%,
var(--disabled-control-bg) 100%
);
// switch
--switch-bg: var(--gray-300);

View file

@ -20,11 +20,14 @@
&--nav {
border-bottom: 1px solid var(--border-color);
}
&--nav-title:hover, &--nav-action:hover {
&--nav-title:hover,
&--nav-action:hover {
background-color: var(--fg-hover-color);
}
&--time-current-hours, &--time-current-minutes, &--time-current-seconds {
&--time-current-hours,
&--time-current-minutes,
&--time-current-seconds {
font-family: inherit;
&:after {
color: var(--text-color);
@ -48,12 +51,14 @@
}
}
&.-range-from-, &.-range-to- {
&.-range-from-,
&.-range-to- {
border: 1px solid var(--border-color);
background: var(--date-range-bg);
}
&.-selected-, &.-current-.-selected- {
&.-selected-,
&.-current-.-selected- {
color: var(--date-active-text);
background: var(--date-active-bg);
border-radius: var(--border-radius-tiny);
@ -79,7 +84,8 @@
}
}
&--time, &--buttons {
&--time,
&--buttons {
border-top: 1px solid var(--border-color);
}
@ -109,4 +115,3 @@
}
}
}

View file

@ -24,7 +24,7 @@
}
.justify-between {
justify-content: space-between
justify-content: space-between;
}
.justify-flex-end {
@ -51,7 +51,8 @@
align-items: center;
}
.level-left, .level-right {
.level-left,
.level-right {
display: flex;
flex-basis: auto;
flex-grow: 0;
@ -84,5 +85,5 @@
}
.fill-width {
flex: 1
flex: 1;
}

View file

@ -27,4 +27,4 @@
font-size: var(--text-xl);
font-weight: 700;
color: var(--heading-color);
}
}

View file

@ -1,7 +1,8 @@
@import "../element/checkbox";
@import "../element/radio";
html, body {
html,
body {
height: 100%;
font-family: var(--font-stack);
font-variation-settings: "opsz" 24;
@ -21,7 +22,8 @@ html, body {
color: var(--text-color);
}
.input-area, .disp-area {
.input-area,
.disp-area {
display: flex;
}
}
@ -57,7 +59,6 @@ html, body {
-moz-appearance: none;
/* for Chrome */
-webkit-appearance: none;
}
.select-icon {
@ -134,7 +135,8 @@ html, body {
.btn-link {
box-shadow: none !important;
outline: none;
.icon, &:hover {
.icon,
&:hover {
text-decoration: none !important;
}
}

View file

@ -31,15 +31,17 @@
}
}
.grid-static-col, .row-check, .row-index {
.grid-static-col,
.row-check,
.row-index {
height: 32px;
padding: 6px 8px !important;
}
.grid-static-col {
padding: 6px 8px !important;
.static-area{
.static-area {
&.reqd:after {
content: ' *';
content: " *";
color: var(--red-400);
}
}
@ -69,7 +71,8 @@
}
// hide row index in 6/4 column child tables
.form-column.col-sm-6, .form-column.col-sm-4 {
.form-column.col-sm-6,
.form-column.col-sm-4 {
.form-grid {
.row-index {
display: none;
@ -98,7 +101,7 @@
.grid-body .data-row {
@include get_textstyle("sm", "regular");
color: var(--text-muted)
color: var(--text-muted);
}
.grid-empty,
@ -219,7 +222,7 @@
padding: 0px !important;
}
.frappe-control[data-fieldtype=Select].form-group .select-icon {
.frappe-control[data-fieldtype="Select"].form-group .select-icon {
top: 9px;
}
@ -287,7 +290,8 @@
margin-left: 1rem;
}
.grid-static-col[data-fieldtype="Code"], .grid-static-col[data-fieldtype="HTML Editor"] {
.grid-static-col[data-fieldtype="Code"],
.grid-static-col[data-fieldtype="HTML Editor"] {
overflow: hidden;
.static-area {
@ -450,7 +454,8 @@
}
}
.grid-buttons, .grid-bulk-actions {
.grid-buttons,
.grid-bulk-actions {
display: inline-flex;
}
@ -460,7 +465,8 @@
.grid-footer {
margin-top: var(--margin-sm);
}
.grid-footer, .grid-custom-buttons {
.grid-footer,
.grid-custom-buttons {
padding: var(--padding-sm) 0px;
background-color: var(--fg-color);
.btn {
@ -517,8 +523,7 @@
}
.grid-footer-toolbar {
padding: var(--padding-md) var(--padding-sm) var(--padding-xs)
var(--padding-sm);
padding: var(--padding-md) var(--padding-sm) var(--padding-xs) var(--padding-sm);
// border-top: 1px solid var(--border-color);
span {
margin-right: var(--margin-xs);
@ -565,10 +570,10 @@
@media (min-width: map-get($grid-breakpoints, "md")) {
.form-grid-container {
overflow-x: unset!important;
overflow-x: unset !important;
.form-grid {
position: unset!important;
position: unset !important;
}
}
}
@ -579,4 +584,3 @@
padding-right: 0 !important;
}
}

View file

@ -12,8 +12,8 @@
cursor: pointer;
/* Hide scrollbar for IE, Edge and Firefox */
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
/* Hide scrollbar for Chrome, Safari and Opera */
&::-webkit-scrollbar {
@ -32,7 +32,7 @@
.search-icons {
position: relative;
input[type='search'] {
input[type="search"] {
height: inherit;
padding-left: 30px;
}
@ -50,7 +50,7 @@
}
}
.frappe-control[data-fieldtype='Icon'] {
.frappe-control[data-fieldtype="Icon"] {
input {
padding-left: 40px;
}
@ -62,7 +62,7 @@
position: absolute;
top: calc(50% + 2px);
left: 8px;
content: ' ';
content: " ";
}
.like-disabled-input {
.icon-value {
@ -88,8 +88,9 @@
}
}
.dt-cell__edit, .filter-field {
.dt-cell__edit,
.filter-field {
.selected-icon {
top: 5px !important;
}
}
}

View file

@ -76,4 +76,4 @@ use.like-icon {
.no-stroke {
stroke: none;
}
}

View file

@ -7,7 +7,7 @@
}
.indicator::before {
content: '';
content: "";
height: 8px;
width: 8px;
border-radius: var(--border-radius);
@ -17,7 +17,7 @@
.indicator-pill-right {
@include get_textstyle("sm", "regular");
padding: 4.5px 8px;
border-radius: var( --border-radius-full);
border-radius: var(--border-radius-full);
height: 20px;
}
@ -31,7 +31,7 @@
.indicator-pill:not(.no-indicator-dot)::before,
.indicator-pill-right::after {
content:'';
content: "";
display: inline-table;
height: 6px;
width: 6px;
@ -48,7 +48,8 @@
margin: 0 0 0 4px;
}
$indicator-colors: green, cyan, blue, orange, yellow, gray, grey, red, pink, darkgrey, purple, light-blue;
$indicator-colors: green, cyan, blue, orange, yellow, gray, grey, red, pink, darkgrey, purple,
light-blue;
@each $color in $indicator-colors {
.indicator.#{"" + $color} {
&::before,
@ -72,11 +73,12 @@ $indicator-colors: green, cyan, blue, orange, yellow, gray, grey, red, pink, dar
}
}
.indicator.blink {
animation: blink 1s linear infinite;
}
@keyframes blink {
50% { opacity: 0.5; }
50% {
opacity: 0.5;
}
}

View file

@ -1,9 +1,4 @@
@mixin flex(
$dis: flex,
$x: center,
$y: center,
$dir: row
) {
@mixin flex($dis: flex, $x: center, $y: center, $dir: row) {
display: $dis;
justify-content: $x;
align-items: $y;
@ -43,7 +38,7 @@
$top: 0,
$left: 0,
$background-color: var(--bg-color),
$border-radius: var(--border-radius),
$border-radius: var(--border-radius)
) {
// Deprecated: Does not work as expected anymore. Also, this never worked in Safari.
}
}

View file

@ -21,7 +21,7 @@ body.modal-open[style^="padding-right"] {
}
// Hide scrollbar on touch devices
@media(max-width: 991px) {
@media (max-width: 991px) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
@ -147,7 +147,6 @@ body.modal-open[style^="padding-right"] {
.hasDatepicker {
z-index: 1140;
}
}
.modal-backdrop.show {
@ -203,7 +202,8 @@ body.modal-open[style^="padding-right"] {
}
}
.modal-body, .modal-footer {
.modal-body,
.modal-footer {
display: none;
}
}
@ -244,7 +244,7 @@ body.modal-open[style^="padding-right"] {
margin-bottom: -24px;
button {
// same as form-control input
height: calc(1.5em + .7rem);
height: calc(1.5em + 0.7rem);
}
}
}
@ -285,7 +285,7 @@ body.modal-open[style^="padding-right"] {
@extend .row;
.btn-group {
opacity: 0;
transition: opacity .3s ease-in-out;
transition: opacity 0.3s ease-in-out;
button {
display: inline-flex;

View file

@ -12,8 +12,8 @@
cursor: pointer;
/* Hide scrollbar for IE, Edge and Firefox */
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
/* Hide scrollbar for Chrome, Safari and Opera */
&::-webkit-scrollbar {
@ -44,7 +44,7 @@
.search-phones {
position: relative;
input[type='search'] {
input[type="search"] {
height: inherit;
padding-left: 30px;
}
@ -59,7 +59,7 @@
.phone-picker-popover {
max-width: 325px;
left: 29px !important;
left: 29px !important;
.picker-arrow {
left: 15px !important;
}
@ -69,9 +69,7 @@
}
}
.frappe-control[data-fieldtype='Phone']
{
.frappe-control[data-fieldtype="Phone"] {
input {
padding-left: 30px;
}
@ -83,7 +81,7 @@
position: absolute;
top: calc(50% + 2px);
left: 8px;
content: ' ';
content: " ";
align-items: center;
z-index: 1;
@ -97,7 +95,6 @@
img {
height: 15px;
}
}
.like-disabled-input {
.phone-value {
@ -111,12 +108,11 @@
}
.modal-body {
.frappe-control[data-fieldtype='Phone']
{
.selected-phone {
top: calc(50% - 0.5px);
}
.frappe-control[data-fieldtype="Phone"] {
.selected-phone {
top: calc(50% - 0.5px);
}
}
}
.data-row.row {
@ -128,7 +124,7 @@
.bg-gray-100 {
--tw-bg-opacity: 1;
background-color: rgba(244,245,246,var(--tw-bg-opacity));
background-color: rgba(244, 245, 246, var(--tw-bg-opacity));
}
.dt-cell__content {
@ -137,7 +133,8 @@
}
}
.dt-cell__edit, .filter-field {
.dt-cell__edit,
.filter-field {
.selected-phone {
top: 5.5px !important;
}

View file

@ -1,5 +1,5 @@
@import '~quill/dist/quill.snow';
@import '~quill/dist/quill.bubble';
@import "~quill/dist/quill.snow";
@import "~quill/dist/quill.bubble";
.ql-toolbar.ql-snow,
.ql-container.ql-snow {
@ -158,7 +158,6 @@
color: var(--text-color);
box-shadow: var(--shadow-base);
}
}
.print-format {
@ -208,7 +207,7 @@
color: var(--code-block-text);
padding: var(--padding-xs) var(--padding-sm) !important;
margin-bottom: var(--margin-xs) !important;
margin-top: var(--margin-xs)!important;
margin-top: var(--margin-xs) !important;
border-radius: var(--border-radius-sm);
}
@ -262,33 +261,33 @@
width: 66px;
.ql-picker-label::before {
content: 'Table';
content: "Table";
}
.ql-picker-options {
[data-value='insert-table']::before {
content: 'Insert Table';
[data-value="insert-table"]::before {
content: "Insert Table";
}
[data-value='insert-row-above']::before {
content: 'Insert Row Above';
[data-value="insert-row-above"]::before {
content: "Insert Row Above";
}
[data-value='insert-row-below']::before {
content: 'Insert Row Below';
[data-value="insert-row-below"]::before {
content: "Insert Row Below";
}
[data-value='insert-column-right']::before {
content: 'Insert Column Right';
[data-value="insert-column-right"]::before {
content: "Insert Column Right";
}
[data-value='insert-column-left']::before {
content: 'Insert Column Left';
[data-value="insert-column-left"]::before {
content: "Insert Column Left";
}
[data-value='delete-row']::before {
content: 'Delete Row';
[data-value="delete-row"]::before {
content: "Delete Row";
}
[data-value='delete-column']::before {
content: 'Delete Column';
[data-value="delete-column"]::before {
content: "Delete Column";
}
[data-value='delete-table']::before {
content: 'Delete Table';
[data-value="delete-table"]::before {
content: "Delete Table";
}
}
}
@ -313,7 +312,6 @@
}
}
.ql-mention-list {
border-radius: var(--border-radius-sm);
list-style: none;
@ -323,7 +321,7 @@
overflow: scroll;
}
.mention>span {
.mention > span {
margin: 0 3px;
}
@ -338,4 +336,4 @@
left: 8px;
color: var(--text-muted);
font-style: normal;
}
}

View file

@ -8,4 +8,4 @@
@import "frappe/public/js/lib/leaflet/leaflet.css";
@import "frappe/public/js/lib/leaflet_easy_button/easy-button.css";
@import "frappe/public/js/lib/leaflet_control_locate/L.Control.Locate.css";
@import "frappe/public/js/lib/leaflet_draw/leaflet.draw.css";
@import "frappe/public/js/lib/leaflet_draw/leaflet.draw.css";

View file

@ -166,7 +166,6 @@
margin-right: var(--margin-xs);
}
.avatar-action {
@extend .avatar-small;
display: flex;

View file

@ -59,12 +59,12 @@ th.fc-widget-header {
}
// .fc-highlight {
// background-color: $light-yellow !important;
// background-color: $light-yellow !important;
// }
.fc-event {
// border: 1px solid #E8DDFF; /* default BORDER color */
background-color: #E8DDFF;
background-color: #e8ddff;
}
.fc-time-grid-event {
@ -137,7 +137,6 @@ th.fc-day-header {
// }
}
.fc-state-active {
box-shadow: none !important;
background: var(--gray-500) !important;
@ -164,7 +163,8 @@ th.fc-day-header {
}
.fc-left {
.fc-prev-button, .fc-next-button {
.fc-prev-button,
.fc-next-button {
width: 28px;
display: flex;
justify-content: center;
@ -205,4 +205,3 @@ th.fc-day-header {
.fc-now-indicator-arrow {
display: none !important;
}

View file

@ -1,17 +1,14 @@
@import '../common/css_variables.scss';
@import "../common/css_variables.scss";
:root,
[data-theme="light"] {
// breakpoints
--xxl-width: #{map-get($grid-breakpoints, '2xl')};
--xl-width: #{map-get($grid-breakpoints, 'xl')};
--lg-width: #{map-get($grid-breakpoints, 'lg')};
--md-width: #{map-get($grid-breakpoints, 'md')};
--sm-width: #{map-get($grid-breakpoints, 'sm')};
--xs-width: #{map-get($grid-breakpoints, 'xs')};
--xxl-width: #{map-get($grid-breakpoints, "2xl")};
--xl-width: #{map-get($grid-breakpoints, "xl")};
--lg-width: #{map-get($grid-breakpoints, "lg")};
--md-width: #{map-get($grid-breakpoints, "md")};
--sm-width: #{map-get($grid-breakpoints, "sm")};
--xs-width: #{map-get($grid-breakpoints, "xs")};
--appreciation-color: var(--green-600);
--appreciation-bg: var(--green-100);

View file

@ -45,7 +45,8 @@ $check-icon-dark: url("data:image/svg+xml, <svg viewBox='0 0 8 7' fill='none' xm
--btn-default-hover-bg: var(--gray-700);
--btn-primary: var(--gray-300);
// Border Colors
--border-primary: var(--gray-200);
// Background Text Color Pairs
--bg-blue: var(--blue-600);
@ -127,15 +128,24 @@ $check-icon-dark: url("data:image/svg+xml, <svg viewBox='0 0 8 7' fill='none' xm
// checkbox
--checkbox-color: var(--neutral-white);
--checkbox-gradient: linear-gradient(180deg, var(--neutral-white) -124.51%, var(--neutral-white) 100%);
--checkbox-disabled-gradient: linear-gradient(180deg, var(--gray-600) -124.51%, var(--gray-600) 100%);
--checkbox-gradient: linear-gradient(
180deg,
var(--neutral-white) -124.51%,
var(--neutral-white) 100%
);
--checkbox-disabled-gradient: linear-gradient(
180deg,
var(--gray-600) -124.51%,
var(--gray-600) 100%
);
--checkbox-focus-shadow: var(--focus-default);
input[type="checkbox"] {
&:checked {
background-image: $check-icon-dark, var(--checkbox-gradient);
}
&.disabled-selected, &:disabled:checked {
&.disabled-selected,
&:disabled:checked {
background-image: $check-icon-dark, var(--checkbox-disabled-gradient);
}
&.disabled-deselected {
@ -152,7 +162,6 @@ $check-icon-dark: url("data:image/svg+xml, <svg viewBox='0 0 8 7' fill='none' xm
--date-active-bg: var(--gray-700);
--date-range-bg: var(--subtle-fg);
// grid
.grid-body .editable-row {
--control-bg: var(--gray-900);
@ -245,7 +254,8 @@ $check-icon-dark: url("data:image/svg+xml, <svg viewBox='0 0 8 7' fill='none' xm
background: var(--gray-500);
}
$indicator-colors: green, cyan, blue, orange, yellow, gray, grey, red, pink, darkgrey, purple, light-blue;
$indicator-colors: green, cyan, blue, orange, yellow, gray, grey, red, pink, darkgrey, purple,
light-blue;
@each $color in $indicator-colors {
.indicator {
--indicator-dot-#{"" + $color}: var(--bg-#{$color});

View file

@ -28,37 +28,36 @@
// .page-form {
// height: 50px;
// .dashboard-header {
// padding: 10px;
// display: flex;
// justify-content: space-between;
// width: 100%;
// .dashboard-header {
// padding: 10px;
// display: flex;
// justify-content: space-between;
// width: 100%;
// .header-title {
// line-height: 1.5em;
// }
// .header-title {
// line-height: 1.5em;
// }
// .restricted-button {
// cursor: default;
// position: relative;
// right: 5px;
// top: -3px;
// }
// }
// .restricted-button {
// cursor: default;
// position: relative;
// right: 5px;
// top: -3px;
// }
// }
// .customize-dashboard {
// font-size: 13px;
// cursor: pointer;
// }
// .customize-dashboard {
// font-size: 13px;
// cursor: pointer;
// }
// .customize-options {
// display: none;
// cursor: pointer;
// .customize-options {
// display: none;
// cursor: pointer;
// .customize-option:hover {
// text-decoration: underline;
// }
// }
// .customize-option:hover {
// text-decoration: underline;
// }
// }
// }
}

View file

@ -569,7 +569,6 @@ body {
}
&.links-widget-box {
.widget-head .widget-label .widget-title svg {
margin: 2px;
margin-right: 12px !important;
@ -588,7 +587,6 @@ body {
border-radius: var(--border-radius-md);
cursor: pointer;
&:first-child {
margin-top: 12px;
}
@ -722,14 +720,17 @@ body {
}
&.quick-list-widget-box {
.list-loading-state, .list-no-data-state {
.list-loading-state,
.list-no-data-state {
display: flex;
justify-content: center;
align-items: center;
height: 202px;
}
.refresh-list, .filter-list, .add-new {
.refresh-list,
.filter-list,
.add-new {
background-color: var(--btn-default-bg);
cursor: pointer;
@ -933,7 +934,8 @@ body {
@media (min-width: map-get($grid-breakpoints, "lg")) {
.layout-main {
height: calc(100vh - var(--navbar-height) - var(--page-head-height) - 5px);
.layout-side-section, .layout-main-section-wrapper {
.layout-side-section,
.layout-main-section-wrapper {
height: 100%;
overflow-y: auto;
scrollbar-color: var(--gray-200) transparent;
@ -988,7 +990,7 @@ body {
padding: var(--padding-sm);
}
.block-menu-item-icon svg{
.block-menu-item-icon svg {
width: 18px;
height: 18px;
margin-right: 5px;
@ -1011,7 +1013,8 @@ body {
display: none;
}
.setting-btn, .duplicate-page {
.setting-btn,
.duplicate-page {
display: none;
}
@ -1063,7 +1066,6 @@ body {
.desk-sidebar {
&.show-hidden-workspaces {
.unhide-workspace-btn {
display: none;
}
@ -1094,14 +1096,16 @@ body {
.standard-sidebar-section.show-control {
.desk-sidebar-item.standard-sidebar-item {
&:hover, &.selected {
&:hover,
&.selected {
.drag-handle {
display: inline-block;
background-color: var(--bg-color);
}
.setting-btn, .duplicate-page, .unhide-workspace-btn {
.setting-btn,
.duplicate-page,
.unhide-workspace-btn {
display: inline-block;
margin-right: 8px;
}
@ -1113,19 +1117,17 @@ body {
}
.block-click {
pointer-events:none;
pointer-events: none;
}
}
}
}
// widgets
.widget.number-widget-box {
border: 1px solid var(--border-color);
}
.codex-editor__loader {
display: none !important;
}
@ -1133,7 +1135,7 @@ body {
.codex-editor {
min-height: 630px;
.codex-editor__redactor{
.codex-editor__redactor {
display: flex;
flex-wrap: wrap;
flex-direction: row;
@ -1168,20 +1170,24 @@ body {
}
.edit-mode {
.widget-control > *, .paragraph-control > * {
.widget-control > *,
.paragraph-control > * {
width: 0px;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s ease-in-out;
}
.link-item, .quick-list-item, .see-all {
.link-item,
.quick-list-item,
.see-all {
pointer-events: none;
}
}
&:hover {
.widget-control > *, .new-block-button {
.widget-control > *,
.new-block-button {
width: auto;
visibility: visible;
opacity: 1;
@ -1201,7 +1207,8 @@ body {
opacity: 1;
}
&.shortcut, &.header {
&.shortcut,
&.header {
background-color: var(--fg-color) !important;
}
@ -1237,7 +1244,7 @@ body {
height: 100%;
padding: 7px;
&> div {
& > div {
height: 100%;
}
@ -1248,7 +1255,7 @@ body {
.resizer {
width: 10px;
height: 100%;
position:absolute;
position: absolute;
right: 0;
bottom: 0;
cursor: col-resize;
@ -1383,7 +1390,6 @@ body {
}
.ce-toolbar {
&.ce-toolbar--opened {
display: none;
}
@ -1403,7 +1409,8 @@ body {
.ce-settings {
width: fit-content;
.ce-settings__button, .cdx-settings-button {
.ce-settings__button,
.cdx-settings-button {
color: #707684;
.icon {
@ -1415,19 +1422,20 @@ body {
color: #388ae5;
}
.cdx-settings-button.disabled{
.cdx-settings-button.disabled {
pointer-events: none;
opacity: .5
opacity: 0.5;
}
.cdx-settings-sidebar{
.cdx-settings-sidebar {
position: absolute;
right: 100%;
top:0;
top: 0;
background: #fff;
width: 108px;
height: 145px;
box-shadow: 0 3px 15px -3px rgba(13,20,33,.13);
border-radius: 0 4px 4px 0;z-index: 0;
box-shadow: 0 3px 15px -3px rgba(13, 20, 33, 0.13);
border-radius: 0 4px 4px 0;
z-index: 0;
}
}
@ -1436,7 +1444,8 @@ body {
}
}
.ce-inline-tool, .ce-inline-toolbar__dropdown {
.ce-inline-tool,
.ce-inline-toolbar__dropdown {
.icon {
fill: currentColor;
}
@ -1456,11 +1465,10 @@ body {
max-width: 760px;
}
}
}
.cdx-marker {
background: rgba(245,235,111,0.29);
background: rgba(245, 235, 111, 0.29);
padding: 3px 0;
}
@ -1515,5 +1523,4 @@ body {
.dropdown-item-icon {
margin-right: 5px;
}
}

View file

@ -70,11 +70,11 @@ input.driver-highlighted-element {
.driver-fix-stacking {
z-index: auto !important;
position: unset !important;
opacity: 1.0 !important;
opacity: 1 !important;
transform: none !important;
filter: none !important;
perspective: none !important;
transform-style: flat !important;
transform-box: border-box !important;
will-change: unset !important;
}
}

View file

@ -1,5 +1,4 @@
.file-view {
.no-result {
.breadcrumbs {
font-size: var(--text-md);
@ -13,7 +12,6 @@
}
.file-grid-view {
.file-grid.folders {
margin-bottom: var(--margin-2xl);
}
@ -59,7 +57,6 @@
display: block;
}
}
}
.file-footer {
@ -101,7 +98,6 @@
}
.file-wrapper:hover {
.list-row-checkbox {
&:before {
display: block;
@ -119,9 +115,8 @@
}
.file-wrapper.cut {
border: 2px dashed var(--dark-border-color)
border: 2px dashed var(--dark-border-color);
}
}
}
}

View file

@ -40,7 +40,6 @@
}
}
}
}
.empty-filters {
@ -104,4 +103,3 @@
}
}
}

View file

@ -1,5 +1,5 @@
@import "../common/form.scss";
@import '~cropperjs/dist/cropper.min';
@import "~cropperjs/dist/cropper.min";
.tooltip-content {
position: absolute;
@ -19,11 +19,10 @@
.show-tooltip .frappe-control:hover .tooltip-content {
opacity: 1;
transform: translate3d(0,0,0);
transform: translate3d(0, 0, 0);
pointer-events: auto;
}
.std-form-layout > .form-layout > .form-page {
border-radius: var(--border-radius-md);
border: 1px solid var(--border-color);
@ -31,7 +30,8 @@
background-color: var(--card-bg);
}
.form-section, .form-dashboard-section {
.form-section,
.form-dashboard-section {
margin: 0px;
.form-section-description {
@ -132,7 +132,8 @@
text-align: right;
}
.form-control:disabled, .form-control[readonly] {
.form-control:disabled,
.form-control[readonly] {
color: var(--text-muted);
cursor: not-allowed;
}
@ -336,7 +337,6 @@
}
}
[data-theme="dark"] .form-message {
&.blue {
@include form-message-background("blue", "dark");
}

View file

@ -26,7 +26,8 @@
background-color: var(--bg-color) !important;
}
.frappe-control, .form-control {
.frappe-control,
.form-control {
margin: 0;
border-radius: 0px;
border: none;
@ -48,7 +49,6 @@
}
.dt-header {
.dt-row[data-is-filter] {
display: flex !important;
}
@ -150,7 +150,8 @@
font-feature-settings: "tnum";
}
.dt-cell__content--header-0, .dt-cell__content--col-0 {
.dt-cell__content--header-0,
.dt-cell__content--col-0 {
padding: 0.5rem;
}

View file

@ -11,8 +11,8 @@ body {
background-color: var(--bg-color);
&.full-width {
@include media-breakpoint-up(md) {
.container {
@include media-breakpoint-up(md) {
.container {
width: 90%;
max-width: 100%;
}
@ -96,22 +96,49 @@ pre {
white-space: pre-wrap;
}
.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;
}
.hidden-xs, .hidden-sm {
.hidden-xs,
.hidden-sm {
@include media-breakpoint-between(xs, sm) {
display: none !important;
}
@ -173,7 +200,6 @@ img {
}
}
.hide-control {
@extend .d-none;
}
@ -186,20 +212,36 @@ img {
text-decoration: none !important;
}
h1, h2, h3, h4 {
h1,
h2,
h3,
h4 {
color: var(--text-color);
margin-bottom: var(--margin-md)
margin-bottom: var(--margin-md);
}
// override default gray-900 from bootstrap to support dark mode.
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
color: var(--heading-color);
}
h1, h2, h3 {
h1,
h2,
h3 {
font-weight: bold;
}
p {
margin-bottom: var(--margin-sm)
margin-bottom: var(--margin-sm);
}
.small {
@ -234,7 +276,8 @@ h2 {
}
}
.btn-group-sm > .btn, .btn-sm {
.btn-group-sm > .btn,
.btn-sm {
padding: var(--padding-xs) var(--padding-sm);
@include get_textstyle("base", "regular");
}
@ -308,7 +351,7 @@ select.input-xs {
.dropdown-item {
border-radius: 8px;
padding : var(--dropdown-padding) !important;
padding: var(--dropdown-padding) !important;
}
.dropdown-menu {
@ -338,7 +381,8 @@ select.input-xs {
--icon-stroke: #{$component-active-color};
}
.divider, .dropdown-divider {
.divider,
.dropdown-divider {
margin: 4px;
}
@ -346,7 +390,8 @@ select.input-xs {
&.dropdown-divider {
display: none;
}
.divider, .dropdown-divider {
.divider,
.dropdown-divider {
display: none;
}
}
@ -392,7 +437,8 @@ kbd {
.table {
color: var(--text-color);
th, td {
th,
td {
padding: 0.5rem;
}
}
@ -499,7 +545,8 @@ kbd {
right: auto !important;
left: 5px;
}
input, textarea {
input,
textarea {
direction: rtl !important;
}
@ -518,7 +565,6 @@ img.no-image {
background-color: var(--bg-light-gray);
}
@media (min-width: 768px) {
.video-modal .modal-dialog {
width: 700px;

View file

@ -100,7 +100,9 @@
}
}
.list-more, .section-more, .results-status {
.list-more,
.section-more,
.results-status {
padding: var(--padding-sm) 0;
color: var(--primary);
@include get_textstyle("sm", "regular");

View file

@ -1,6 +1,5 @@
// Image view
.image-view {
.frappe-list {
padding: var(--padding-xs);
}
@ -24,7 +23,6 @@
margin-left: var(--margin-xs);
}
}
}
.image-view-container {
@ -200,15 +198,13 @@
// opacity: 0.5
// }
}
}
}
.pswp--svg .pswp__button,
.pswp--svg .pswp__button--arrow--left:before,
.pswp--svg .pswp__button--arrow--right:before {
background-image: url('/assets/frappe/images/default-skin.svg') !important;
background-image: url("/assets/frappe/images/default-skin.svg") !important;
}
.pswp--svg .pswp__button--arrow--left,
.pswp--svg .pswp__button--arrow--right {
@ -234,8 +230,7 @@
cursor: pointer;
border: 1px solid var(--border-color);
img {
max-height: 100%;
}
}
}

View file

@ -160,10 +160,7 @@
@include flex(flex, space-between, null, column);
margin-top: var(--margin-sm);
min-height: 100px;
@include card(
$padding: 0,
$background-color: var(--kanban-card-bg)
);
@include card($padding: 0, $background-color: var(--kanban-card-bg));
box-shadow: none;
border: 1px solid var(--border-color);
@ -207,7 +204,6 @@
}
.kanban-card-meta {
.list-comment-count {
width: 30px;
}

View file

@ -40,7 +40,6 @@
overflow-wrap: break-word;
.preview-field {
.preview-label {
padding-bottom: 4px;
}

View file

@ -4,7 +4,9 @@
// }
.freeze-row {
.level-left, .level-right, .list-row-col {
.level-left,
.level-right,
.list-row-col {
height: 100%;
width: 100%;
}
@ -41,7 +43,8 @@
}
.no-list-sidebar {
&[data-page-route^="List/"], [data-page-route^="List/"]{
&[data-page-route^="List/"],
[data-page-route^="List/"] {
@include media-breakpoint-up(md) {
.layout-side-section {
display: none;
@ -67,7 +70,6 @@
background-color: var(--highlight-color);
}
}
}
.list-row {
@ -117,7 +119,7 @@
justify-content: flex-end;
// min-width: 120px;
&> span {
& > span {
display: inline-block;
}
@ -135,7 +137,8 @@
white-space: nowrap;
}
.list-assignments, .list-actions {
.list-assignments,
.list-actions {
margin-right: var(--margin-md);
}
}
@ -146,7 +149,8 @@
}
}
.select-like, .file-select {
.select-like,
.file-select {
padding-left: 11px;
}
}
@ -155,10 +159,10 @@
@extend .list-row;
cursor: default;
background-color: var(--subtle-fg);
height: 30px;
height: 30px;
padding: 8px, 10px, 8px, 0px;
margin: 8px 5px;
border-radius: var(--border-radius-md);
border-radius: var(--border-radius-md);
.list-check-all {
margin-left: 11px;
@ -201,7 +205,8 @@ $level-margin-right: 8px;
}
}
.list-paging-area, .footnote-area {
.list-paging-area,
.footnote-area {
border-top: 1px solid var(--border-color);
.btn-group {
@ -214,7 +219,7 @@ $level-margin-right: 8px;
background-color: var(--bg-color);
color: var(--text-color);
font-weight: var(--weight-medium);
}
}
}
.btn-paging {
background-color: var(--gray-50);
@ -222,7 +227,8 @@ $level-margin-right: 8px;
}
.frappe-card {
.list-paging-area, .footnote-area {
.list-paging-area,
.footnote-area {
padding: var(--padding-md);
}
}
@ -239,7 +245,8 @@ $level-margin-right: 8px;
margin-bottom: 1px;
}
input.list-check-all, input.list-row-checkbox {
input.list-check-all,
input.list-row-checkbox {
margin-top: 0px;
margin-bottom: 0px;
--checkbox-right-margin: calc(var(--checkbox-size) / 2 + #{$level-margin-right});
@ -315,12 +322,13 @@ input.list-check-all {
cursor: auto;
}
input[type=checkbox] {
input[type="checkbox"] {
margin: 0;
margin-right: 5px;
}
.liked-by, .liked-by-filter-button {
.liked-by,
.liked-by-filter-button {
display: inline-block;
width: 20px;
margin-right: 10px;
@ -343,7 +351,8 @@ input.list-check-all {
margin-right: 5px;
min-width: 110px;
.list-row-modified, .avatar-small {
.list-row-modified,
.avatar-small {
margin-right: 10px;
}
}
@ -425,7 +434,6 @@ input.list-check-all {
margin: var(--margin-xs) 0 var(--margin-xs) var(--margin-xs);
}
}
}
.restricted-button {
@ -441,10 +449,7 @@ input.list-check-all {
}
&.btn {
@include button-variant(
$background: $light-yellow,
$border: darken($light-yellow, 5%),
);
@include button-variant($background: $light-yellow, $border: darken($light-yellow, 5%));
box-shadow: none;
}
}

View file

@ -17,7 +17,7 @@ body {
}
}
@media(max-width: 991px) {
@media (max-width: 991px) {
.intro-area,
.footnote-area {
padding: 15px;
@ -45,7 +45,6 @@ body {
margin-right: var(--margin-xs);
}
.page-head .sub-heading {
font-size: var(--text-xs);
}
@ -80,7 +79,7 @@ body {
white-space: nowrap;
text-overflow: ellipsis;
@media(max-width: 480px) {
@media (max-width: 480px) {
li > a {
width: 100px;
}
@ -98,7 +97,7 @@ body {
}
// select all except last 2
#navbar-breadcrumbs li:not(:nth-last-child(-n+1)) {
#navbar-breadcrumbs li:not(:nth-last-child(-n + 1)) {
display: none;
}
@ -161,9 +160,8 @@ body {
// }
}
@media(max-width: 767px) {
body[data-route^="Form"]{
@media (max-width: 767px) {
body[data-route^="Form"] {
.page-title {
.title-text {
@include get_textstyle("lg", "regular");
@ -256,14 +254,13 @@ body {
top: 4px;
// bigger indicators for list
.indicator::before, .indicator::after {
.indicator::before,
.indicator::after {
height: 12px;
width: 12px;
border-radius: 12px;
}
}
}
.list-row-right.no-right-column {
@ -272,7 +269,6 @@ body {
right: 10px;
left: -10px;
width: 100%;
}
}
@ -346,12 +342,13 @@ body {
margin-right: 0;
}
}
.comment-header{
.comment-header {
padding: 7px 10px;
.links-active {
padding-right: 10px;
}
.reply-link, .reply-link-all {
.reply-link,
.reply-link-all {
margin-left: 0;
}
.asset-details {
@ -364,10 +361,10 @@ body {
.reply {
padding: 10px;
}
.commented-on-small{
.commented-on-small {
display: inline-block;
}
.commented-on-small{
.commented-on-small {
display: inline-block;
}
}

View file

@ -30,7 +30,7 @@
padding: 30px;
}
@media(min-width: map-get($grid-breakpoints, "md")) {
@media (min-width: map-get($grid-breakpoints, "md")) {
.module-section:nth-child(even) {
background-color: var(--bg-color);
}
@ -40,21 +40,21 @@
}
}
@media(max-width: map-get($grid-breakpoints, "lg")) {
@media (max-width: map-get($grid-breakpoints, "lg")) {
.module-body {
margin-top: 15px;
border-top: 1px solid $border-color;
}
}
@media(max-width: map-get($grid-breakpoints, "md")) {
@media (max-width: map-get($grid-breakpoints, "md")) {
.module-body {
margin-top: 0;
border-top: 1px solid transparent;
}
}
@media(max-width: map-get($grid-breakpoints, "md")) {
@media (max-width: map-get($grid-breakpoints, "md")) {
.module-section {
border: none;
}
@ -72,7 +72,6 @@
}
}
.module-item {
margin: 0px;
padding: 7px;
@ -96,7 +95,8 @@
margin-left: 3px;
}
.module-item:hover, .module-item:focus {
.module-item:hover,
.module-item:focus {
background-color: var(--bg-color);
}
@ -126,14 +126,12 @@
width: 0px;
}
@media(max-width: map-get($grid-breakpoints, "md")) {
@media (max-width: map-get($grid-breakpoints, "md")) {
body[data-route^="Module"] {
.page-title {
width: 100%;
}
.page-actions {
display: none !important;
}

View file

@ -64,7 +64,8 @@
max-height: 450px;
overflow-y: auto;
.panel-events, .panel-notifications {
.panel-events,
.panel-notifications {
@include size(100%, null);
}
@ -134,14 +135,13 @@
.recent-item.notification-item {
padding: 10px 10px 10px 0px;
margin: 10px 10px 10px 10px;
margin: 10px 10px 10px 10px;
justify-content: space-between;
&.unread {
&:hover {
.mark-as-read {
flex-shrink : 0;
flex-shrink: 0;
align-self: center;
justify-self: end;
width: 8px;
@ -161,12 +161,12 @@
gap: 10px;
&::before {
content: '';
content: "";
display: inline-block;
@include size(6px, 6px);
min-width: 6px;
margin-top: 16px;
margin-left: 2px;
margin-left: 2px;
border-radius: 10px;
}
@ -177,7 +177,7 @@
b {
font-weight: 500;
color: var(--text-light)
color: var(--text-light);
}
.notification-timestamp {
@ -293,7 +293,7 @@
&:hover {
text-decoration: none;
color: var(--text-color)
color: var(--text-color);
}
}
@ -315,4 +315,4 @@
margin-left: 5px;
}
}
}
}

View file

@ -10,7 +10,8 @@
display: none;
}
.sidebar-toggle-icon, .sidebar-toggle-placeholder {
.sidebar-toggle-icon,
.sidebar-toggle-placeholder {
@include transition(all 0.5s ease-in-out);
}
@ -42,7 +43,6 @@
}
}
.page-container {
background-color: var(--bg-color);
@ -60,7 +60,8 @@
border-radius: var(--border-radius);
line-height: 1;
padding: 4px 8px;
&, & .hidden-xs {
&,
& .hidden-xs {
display: inline-flex;
align-items: center;
gap: 6px;
@ -69,7 +70,8 @@
.btn:not(.icon-btn) {
padding: 4px 8px;
}
.btn-primary, .btn-secondary {
.btn-primary,
.btn-secondary {
min-width: 40px;
}
.custom-btn-group {
@ -90,7 +92,7 @@
overflow: hidden;
@include card($padding: 0px);
box-shadow: none;
border: 1px solid var(--border-color)
border: 1px solid var(--border-color);
}
.page-head {
@ -144,7 +146,9 @@
}
}
.menu-btn-group, .custom-btn-group, .page-icon-group {
.menu-btn-group,
.custom-btn-group,
.page-icon-group {
display: flex;
.dropdown-menu {
width: max-content;
@ -159,10 +163,13 @@
}
}
.layout-main-section {
.frappe-list, .report-wrapper {
.frappe-list,
.report-wrapper {
padding: 0 var(--padding-xs);
.result, .no-result, .freeze {
.result,
.no-result,
.freeze {
min-height: #{"calc(100vh - 284px)"};
}
}

View file

@ -8,4 +8,4 @@
.plyr__poster {
filter: brightness(0.7);
}
}
}

View file

@ -45,7 +45,6 @@
.layout-side-section.print-preview-sidebar {
padding-right: var(--padding-md);
.label-area {
white-space: nowrap;
}
@ -73,7 +72,6 @@
}
.skeleton-body {
.skeleton-table {
width: 100%;
@ -144,9 +142,8 @@
background-position: -100px;
}
50%, 100% {
50%,
100% {
background-position: 500px;
}
}

View file

@ -29,7 +29,7 @@
.grid-report .show-zero {
margin: 10px;
display: none
display: none;
}
// column picker
@ -183,9 +183,15 @@
color: var(--text-color);
font-feature-settings: "tnum";
&.green { color: var(--green-500); }
&.red { color: var(--red-500); }
&.blue { color: var(--blue-500); }
&.green {
color: var(--green-500);
}
&.red {
color: var(--red-500);
}
&.blue {
color: var(--blue-500);
}
// SIZE & SPACING
padding-top: 12px;
@ -214,9 +220,15 @@
border-radius: var(--border-radius-sm, 4px);
border: 1px solid var(--dark-border-color);
&.green { color: var(--green-500); }
&.red { color: var(--red-500); }
&.blue { color: var(--blue-500); }
&.green {
color: var(--green-500);
}
&.red {
color: var(--red-500);
}
&.blue {
color: var(--blue-500);
}
// SIZE & SPACING
min-width: 24px;

View file

@ -4,7 +4,8 @@ table.user-perm {
overflow-x: scroll;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
tr td, tr th {
tr td,
tr th {
padding: 5px;
border-bottom: 1px solid var(--border-color);
min-width: 30px;
@ -12,7 +13,7 @@ table.user-perm {
text-align: center;
}
}
--icon-stroke: var(--text-muted)
--icon-stroke: var(--text-muted);
}
.frappe-control {
@ -28,7 +29,7 @@ table.user-perm {
label {
position: relative;
}
input[type=checkbox] {
input[type="checkbox"] {
margin-left: 0;
}
}
@ -46,4 +47,4 @@ table.user-perm {
.module-block-list .checkbox {
margin-bottom: var(--margin-xs);
font-size: var(--text-md);
}
}

View file

@ -44,7 +44,6 @@ body[data-route^="Module"] .main-menu {
.es-icon {
margin: 0px 6px;
}
}
&.user-actions {
margin-bottom: 15px;
@ -84,7 +83,6 @@ body[data-route^="Module"] .main-menu {
}
.form-tags {
.form-tag-row:not(:last-child) {
margin-bottom: var(--margin-sm);
}
@ -256,7 +254,6 @@ body[data-route^="Module"] .main-menu {
background-color: var(--border-color);
opacity: 0.7;
}
}
@media (max-width: 767px) {
@ -383,7 +380,7 @@ body[data-route^="Module"] .main-menu {
display: none;
}
input:not([data-fieldtype='Check']) {
input:not([data-fieldtype="Check"]) {
background: var(--control-bg-on-gray);
}
@ -403,7 +400,8 @@ body[data-route^="Module"] .main-menu {
margin-bottom: 10px;
}
.attachment-row, .form-tag-row {
.attachment-row,
.form-tag-row {
margin-bottom: 3px;
max-width: 100%;
.data-pill {
@ -446,13 +444,14 @@ body[data-route^="Module"] .main-menu {
margin-left: var(--margin-md);
margin-bottom: var(--margin-sm);
color: var(--text-light);
}
.form-assignments {
margin-top: 12px;
}
.form-assignments, .form-shared {
.assignments, .shares {
.form-assignments,
.form-shared {
.assignments,
.shares {
margin: var(--margin-xs) 0px;
}
}
@ -568,4 +567,4 @@ body[data-route^="Module"] .main-menu {
.shared-user {
margin-bottom: 10px;
}
}

View file

@ -13,4 +13,4 @@
.tag-pill {
background-color: var(--gray-900);
}
}
}

View file

@ -112,4 +112,4 @@
background: var(--gray-900);
position: absolute;
}
}
}

View file

@ -9,7 +9,9 @@ $threshold: 34;
// doing this will prevent cssnano from converting 0px to 0
// clamp requires value unit to be valid
--zero-px: 0px;
top: unquote("clamp(var(--zero-px), 50% - #{$badge-size}/2, max(var(--zero-px), (#{$threshold}px - (50% - #{$badge-size}/2)) * #{$threshold}))");
top: unquote(
"clamp(var(--zero-px), 50% - #{$badge-size}/2, max(var(--zero-px), (#{$threshold}px - (50% - #{$badge-size}/2)) * #{$threshold}))"
);
left: calc(-1 * (#{$badge-size} / 2));
background-color: var(--timeline-badge-bg);
@extend .center-content;
@ -24,7 +26,7 @@ $threshold: 34;
padding-left: calc(var(--padding-sm) + var(--timeline-item-icon-size) / 2);
}
&:before {
content: ' ';
content: " ";
top: 90px; // TODO: get top and bottom programmatically
left: calc(var(--timeline-item-icon-size) / 2);
position: absolute;
@ -36,18 +38,20 @@ $threshold: 34;
left: calc(-1.25 * var(--timeline-item-left-margin) / 2);
background: var(--bg-color);
&:before {
content: ' ';
content: " ";
background: var(--timeline-badge-color);
border-radius: 50%;
height: 4px;
width: 4px;
}
}
.activity-title, .timeline-actions {
.activity-title,
.timeline-actions {
margin-bottom: 0 !important;
display: flex;
align-items: center;
.show-all-activity, .timeline-item {
.show-all-activity,
.timeline-item {
margin-bottom: 0;
}
min-height: 60px;
@ -106,9 +110,9 @@ $threshold: 34;
margin: 0 var(--margin-sm);
}
.content{
.content {
padding-left: 42px;
.mention{
.mention {
background-color: transparent;
border: none;
font-weight: var(--weight-semibold);
@ -120,7 +124,6 @@ $threshold: 34;
.timeline-badge {
@include timeline-badge(var(--timeline-item-icon-size));
left: calc(-1 * var(--timeline-item-left-margin));
}
.timeline-load-more {
margin-left: calc(var(--timeline-item-left-margin) + var(--padding-sm));
@ -133,7 +136,7 @@ $threshold: 34;
overflow: auto;
max-height: 500px;
&::before {
content: '';
content: "";
display: block;
height: 1px;
margin-top: -10px;
@ -157,7 +160,8 @@ $threshold: 34;
background-color: transparent;
--icon-stroke: var(--text-muted);
}
.action-btn, .custom-actions {
.action-btn,
.custom-actions {
@include get_textstyle("sm", "regular");
}

View file

@ -97,7 +97,7 @@
color: var(--text-light);
&:hover {
color: var(--text-color)
color: var(--text-color);
}
&:last-child {
@ -138,7 +138,9 @@
}
@keyframes backOutRight {
0% { opacity: 1; }
0% {
opacity: 1;
}
100% {
-webkit-transform: translateX(2000px);

View file

@ -107,7 +107,8 @@
// decoration
// .tree, .tree-node {
.tree.with-skeleton, .tree.with-skeleton .tree-node {
.tree.with-skeleton,
.tree.with-skeleton .tree-node {
position: relative;
// &.opened::before, &:last-child::after {
@ -158,4 +159,4 @@
.tree-node.hover-active {
background-color: var(--fg-hover-color);
border-radius: var(--border-radius-sm);
}
}

View file

@ -25,4 +25,4 @@ $h2-font-size: 1.5rem;
$h3-font-size: 1.25rem;
$h4-font-size: 1.125rem;
$h5-font-size: 0.875rem;
$h6-font-size: 0.6875rem;
$h6-font-size: 0.6875rem;

View file

@ -97,4 +97,4 @@
}
}
}
}
}

View file

@ -4,11 +4,11 @@
@import "../espresso/shadows";
@import "../espresso/borders";
html, body {
html,
body {
font-size: 16px;
}
$border-color: var(--border-color);
$code-color: var(--purple-600);
@ -19,15 +19,15 @@ $border-radius-lg: var(--border-radius-lg);
$nav-divider-margin-y: 4px;
$container-max-widths: (
sm: 540px,
md: 840px,
lg: 1090px,
xl: 1290px
sm: 540px,
md: 840px,
lg: 1090px,
xl: 1290px,
);
$theme-colors: (
"primary": $primary,
"danger": $danger
"primary": $primary,
"danger": $danger,
);
$navbar-height: 48px;
@ -77,7 +77,7 @@ $btn-font-weight: 400 !default;
$btn-active-box-shadow: var(--shadow-inset);
// mark
$mark-bg: #FDF9AF;
$mark-bg: #fdf9af;
$mark-padding: 0;
// transitions
@ -88,7 +88,7 @@ $input-transition: none;
$enable-shadows: true;
$popover-border-radius: 12px;
$popover-bg: var(--popover-bg);
$popover-box-shadow: var(--shadow-2xl);
$popover-box-shadow: var(--shadow-2xl);
$popover-body-padding-x: var(--padding-md);
$popover-body-padding-y: var(--padding-md);
$popover-border-color: transparent;
@ -119,17 +119,17 @@ $dropdown-item-padding-x: var(--padding-sm);
$spacer: 14px;
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
2xl: 1440px
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
2xl: 1440px,
) !default;
@import 'typography';
@import '~bootstrap/scss/functions';
@import '~bootstrap/scss/variables';
@import "typography";
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";
@import 'css_variables';
@import 'dark';
@import "css_variables";
@import "dark";

View file

@ -22,7 +22,8 @@
[data-theme="dark"] {
.version-info {
.danger, .success {
.danger,
.success {
color: var(--gray-900);
td {
@ -30,4 +31,4 @@
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more