mirror of
https://github.com/frappe/books.git
synced 2025-02-08 15:08:29 +00:00
incr: add scaled container
- allow changing the scale of the print view - prevent deletion of non custom templates
This commit is contained in:
parent
6cf4a5ec0c
commit
c04098a3eb
@ -9,6 +9,14 @@ export class PrintTemplate extends Doc {
|
|||||||
template?: string;
|
template?: string;
|
||||||
isCustom?: boolean;
|
isCustom?: boolean;
|
||||||
|
|
||||||
|
override get canDelete(): boolean {
|
||||||
|
if (this.isCustom === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.canDelete;
|
||||||
|
}
|
||||||
|
|
||||||
static getListViewSettings(): ListViewSettings {
|
static getListViewSettings(): ListViewSettings {
|
||||||
return {
|
return {
|
||||||
formRoute: ({ name }) => `/template-builder/${name}`,
|
formRoute: ({ name }) => `/template-builder/${name}`,
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
"fieldname": "isCustom",
|
"fieldname": "isCustom",
|
||||||
"label": "Is Custom",
|
"label": "Is Custom",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"default": false,
|
"default": true,
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -166,6 +166,10 @@ export default {
|
|||||||
const { onboardingComplete } = await fyo.doc.getDoc('GetStarted');
|
const { onboardingComplete } = await fyo.doc.getDoc('GetStarted');
|
||||||
const { hideGetStarted } = await fyo.doc.getDoc('SystemSettings');
|
const { hideGetStarted } = await fyo.doc.getDoc('SystemSettings');
|
||||||
|
|
||||||
|
if (fyo.store.isDevelopment) {
|
||||||
|
return routeTo('/list/PrintTemplate');
|
||||||
|
}
|
||||||
|
|
||||||
if (hideGetStarted || onboardingComplete) {
|
if (hideGetStarted || onboardingComplete) {
|
||||||
routeTo('/');
|
routeTo('/');
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
:value="value"
|
:value="value"
|
||||||
:placeholder="inputPlaceholder"
|
:placeholder="inputPlaceholder"
|
||||||
:readonly="isReadOnly"
|
:readonly="isReadOnly"
|
||||||
|
:step="step"
|
||||||
:max="df.maxvalue"
|
:max="df.maxvalue"
|
||||||
:min="df.minvalue"
|
:min="df.minvalue"
|
||||||
@blur="(e) => !isReadOnly && triggerChange(e.target.value)"
|
@blur="(e) => !isReadOnly && triggerChange(e.target.value)"
|
||||||
@ -32,6 +33,7 @@ export default {
|
|||||||
name: 'Base',
|
name: 'Base',
|
||||||
props: {
|
props: {
|
||||||
df: Object,
|
df: Object,
|
||||||
|
step: { type: Number, default: 1 },
|
||||||
value: [String, Number, Boolean, Object],
|
value: [String, Number, Boolean, Object],
|
||||||
inputClass: [Function, String, Object],
|
inputClass: [Function, String, Object],
|
||||||
border: { type: Boolean, default: false },
|
border: { type: Boolean, default: false },
|
||||||
|
49
src/pages/TemplateBuilder/ScaledContainer.vue
Normal file
49
src/pages/TemplateBuilder/ScaledContainer.vue
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<div class="overflow-hidden" :style="outerContainerStyle">
|
||||||
|
<div :style="innerContainerStyle">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
/**
|
||||||
|
* This Component is required because * CSS transforms (eg
|
||||||
|
* scale) don't change the area taken by * an element.
|
||||||
|
*
|
||||||
|
* So to circumvent this, the outer element needs to have
|
||||||
|
* the scaled dimensions without applying a CSS transform.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
height: { type: String, default: '29.7cm' },
|
||||||
|
width: { type: String, default: '21cm' },
|
||||||
|
scale: { type: Number, default: 0.65 },
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
innerContainerStyle(): Record<string, string> {
|
||||||
|
const style: Record<string, string> = {};
|
||||||
|
style['width'] = this.width;
|
||||||
|
style['height'] = this.height;
|
||||||
|
style['transform'] = `scale(${this.scale})`;
|
||||||
|
style['margin-top'] = `calc(-1 * (${this.height} * ${
|
||||||
|
1 - this.scale
|
||||||
|
}) / 2)`;
|
||||||
|
style['margin-left'] = `calc(-1 * (${this.width} * ${
|
||||||
|
1 - this.scale
|
||||||
|
}) / 2)`;
|
||||||
|
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
outerContainerStyle(): Record<string, string> {
|
||||||
|
const style: Record<string, string> = {};
|
||||||
|
style['height'] = `calc(${this.scale} * ${this.height})`;
|
||||||
|
style['width'] = `calc(${this.scale} * ${this.width})`;
|
||||||
|
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -14,40 +14,50 @@
|
|||||||
</PageHeader>
|
</PageHeader>
|
||||||
<!-- Template Builder Body -->
|
<!-- Template Builder Body -->
|
||||||
<div
|
<div
|
||||||
class="w-full h-full bg-gray-25 grid"
|
class="w-full overflowauto bg-gray-25 grid"
|
||||||
style="grid-template-columns: auto var(--w-quick-edit)"
|
style="
|
||||||
|
grid-template-columns: auto var(--w-quick-edit);
|
||||||
|
height: calc(100vh - var(--h-row-largest) - 1px);
|
||||||
|
"
|
||||||
v-if="doc"
|
v-if="doc"
|
||||||
>
|
>
|
||||||
<!-- Print View Container -->
|
<!-- Template Display Area -->
|
||||||
<div class="overflow-auto custom-scroll">
|
<div class="overflow-auto custom-scroll p-4">
|
||||||
<!-- Display Hints -->
|
<!-- Display Hints -->
|
||||||
<div v-if="helperText" class="p-4 text-sm text-gray-700">
|
<div v-if="helperText" class="text-sm text-gray-700">
|
||||||
{{ helperText }}
|
{{ helperText }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<!-- Template Container -->
|
||||||
v-if="doc.template && values && !helperText"
|
<ScaledContainer
|
||||||
ref="printContainer"
|
v-if="doc.template && values"
|
||||||
class="h-full shadow-lg border bg-white"
|
:scale="Math.max(scale, 0.1)"
|
||||||
style="
|
ref="scaledContainer"
|
||||||
width: 21cm;
|
class="mx-auto shadow-lg border"
|
||||||
height: 29.7cm;
|
|
||||||
transform: scale(0.65);
|
|
||||||
margin-top: -150px;
|
|
||||||
margin-left: -100px;
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
|
<!-- Template -->
|
||||||
<component
|
<component
|
||||||
class="flex-1"
|
class="flex-1 bg-white"
|
||||||
:doc="values.doc"
|
:doc="values.doc"
|
||||||
:print="values.print"
|
:print="values.print"
|
||||||
:is="{ template: doc.template, props: ['doc', 'print'] }"
|
:is="{ template: doc.template, props: ['doc', 'print'] }"
|
||||||
/>
|
/>
|
||||||
</div>
|
</ScaledContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Template Builder Controls -->
|
<!-- Template Builder Controls -->
|
||||||
<div class="h-full w-full ml-auto border-l flex flex-col bg-white">
|
<div
|
||||||
|
class="
|
||||||
|
h-full
|
||||||
|
w-full
|
||||||
|
ml-auto
|
||||||
|
border-l
|
||||||
|
flex flex-col
|
||||||
|
bg-white
|
||||||
|
overflow-auto
|
||||||
|
custom-scroll
|
||||||
|
"
|
||||||
|
>
|
||||||
<!-- Print Template Fields -->
|
<!-- Print Template Fields -->
|
||||||
<div class="p-4 flex flex-col gap-4">
|
<div class="p-4 flex flex-col gap-4">
|
||||||
<FormControl
|
<FormControl
|
||||||
@ -62,7 +72,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Controls -->
|
<!-- Controls Section -->
|
||||||
<div class="p-4 border-t">
|
<div class="p-4 border-t">
|
||||||
<div
|
<div
|
||||||
class="flex justify-between items-center cursor-pointer select-none"
|
class="flex justify-between items-center cursor-pointer select-none"
|
||||||
@ -99,18 +109,25 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<FormControl
|
<FormControl
|
||||||
v-if="doc.isCustom"
|
v-if="displayDoc && doc.template"
|
||||||
size="small"
|
size="small"
|
||||||
:df="fields.isCustom"
|
:step="0.01"
|
||||||
|
:df="{
|
||||||
|
fieldtype: 'Float',
|
||||||
|
label: t`Display Scale`,
|
||||||
|
fieldname: 'displayScale',
|
||||||
|
maxvalue: 10,
|
||||||
|
minvalue: 0.1,
|
||||||
|
}"
|
||||||
:show-label="true"
|
:show-label="true"
|
||||||
:border="true"
|
:border="true"
|
||||||
:read-only="true"
|
:value="scale"
|
||||||
:value="doc.get('isCustom')"
|
@change="(value: number) => scale = value"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Template -->
|
<!-- Template Section -->
|
||||||
<div class="p-4 border-t" v-if="doc.type">
|
<div class="p-4 border-t" v-if="doc.type">
|
||||||
<div
|
<div
|
||||||
class="flex justify-between items-center cursor-pointer select-none"
|
class="flex justify-between items-center cursor-pointer select-none"
|
||||||
@ -125,7 +142,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Template Container -->
|
<!-- Template Editor -->
|
||||||
<textarea
|
<textarea
|
||||||
v-if="!templateCollapsed"
|
v-if="!templateCollapsed"
|
||||||
style="
|
style="
|
||||||
@ -197,6 +214,7 @@ import {
|
|||||||
import { getActionsForDoc, getDocFromNameIfExistsElseNew } from 'src/utils/ui';
|
import { getActionsForDoc, getDocFromNameIfExistsElseNew } from 'src/utils/ui';
|
||||||
import { getMapFromList } from 'utils/index';
|
import { getMapFromList } from 'utils/index';
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
|
import ScaledContainer from './ScaledContainer.vue';
|
||||||
import TemplateBuilderHint from './TemplateBuilderHint.vue';
|
import TemplateBuilderHint from './TemplateBuilderHint.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -209,6 +227,7 @@ export default defineComponent({
|
|||||||
FormHeader,
|
FormHeader,
|
||||||
TemplateBuilderHint,
|
TemplateBuilderHint,
|
||||||
DropdownWithActions,
|
DropdownWithActions,
|
||||||
|
ScaledContainer,
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return { doc: computed(() => this.doc) };
|
return { doc: computed(() => this.doc) };
|
||||||
@ -222,6 +241,7 @@ export default defineComponent({
|
|||||||
templateCollapsed: false,
|
templateCollapsed: false,
|
||||||
helpersCollapsed: true,
|
helpersCollapsed: true,
|
||||||
displayDoc: null,
|
displayDoc: null,
|
||||||
|
scale: 0.65,
|
||||||
} as {
|
} as {
|
||||||
hint: null | Record<string, unknown>;
|
hint: null | Record<string, unknown>;
|
||||||
values: null | Record<string, unknown>;
|
values: null | Record<string, unknown>;
|
||||||
@ -230,6 +250,7 @@ export default defineComponent({
|
|||||||
displayDoc: PrintTemplate | null;
|
displayDoc: PrintTemplate | null;
|
||||||
templateCollapsed: boolean;
|
templateCollapsed: boolean;
|
||||||
helpersCollapsed: boolean;
|
helpersCollapsed: boolean;
|
||||||
|
scale: number;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
@ -239,20 +260,11 @@ export default defineComponent({
|
|||||||
this.helpersCollapsed = false;
|
this.helpersCollapsed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.fyo.store.isDevelopment) {
|
if (this.fyo.store.isDevelopment) {
|
||||||
return;
|
// @ts-ignore
|
||||||
|
window.tb = this;
|
||||||
|
this.setDisplayDoc('SINV-1001');
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
window.tb = this;
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
window.hints = getPrintTemplatePropHints;
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
window.values = getPrintTemplatePropValues;
|
|
||||||
|
|
||||||
this.setDisplayDoc('SINV-1001');
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async makePDF() {
|
async makePDF() {
|
||||||
@ -261,7 +273,12 @@ export default defineComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const innerHTML = (this.$refs.printContainer as HTMLDivElement).innerHTML;
|
// @ts-ignore
|
||||||
|
const innerHTML = this.$refs.scaledContainer.$el.children[0].innerHTML;
|
||||||
|
if (!innerHTML) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await getPathAndMakePDF(displayDoc.name!, innerHTML);
|
await getPathAndMakePDF(displayDoc.name!, innerHTML);
|
||||||
},
|
},
|
||||||
async sync() {
|
async sync() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user