2
0
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:
18alantom 2023-02-24 12:14:58 +05:30
parent 6cf4a5ec0c
commit c04098a3eb
6 changed files with 121 additions and 41 deletions

View File

@ -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}`,

View File

@ -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
} }
] ]

View File

@ -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 {

View File

@ -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 },

View 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>

View File

@ -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() {