mirror of
https://github.com/frappe/books.git
synced 2024-11-09 23:30:56 +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;
|
||||
isCustom?: boolean;
|
||||
|
||||
override get canDelete(): boolean {
|
||||
if (this.isCustom === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.canDelete;
|
||||
}
|
||||
|
||||
static getListViewSettings(): ListViewSettings {
|
||||
return {
|
||||
formRoute: ({ name }) => `/template-builder/${name}`,
|
||||
|
@ -27,7 +27,7 @@
|
||||
"fieldname": "isCustom",
|
||||
"label": "Is Custom",
|
||||
"fieldtype": "Check",
|
||||
"default": false,
|
||||
"default": true,
|
||||
"readOnly": true
|
||||
}
|
||||
]
|
||||
|
@ -166,6 +166,10 @@ export default {
|
||||
const { onboardingComplete } = await fyo.doc.getDoc('GetStarted');
|
||||
const { hideGetStarted } = await fyo.doc.getDoc('SystemSettings');
|
||||
|
||||
if (fyo.store.isDevelopment) {
|
||||
return routeTo('/list/PrintTemplate');
|
||||
}
|
||||
|
||||
if (hideGetStarted || onboardingComplete) {
|
||||
routeTo('/');
|
||||
} else {
|
||||
|
@ -13,6 +13,7 @@
|
||||
:value="value"
|
||||
:placeholder="inputPlaceholder"
|
||||
:readonly="isReadOnly"
|
||||
:step="step"
|
||||
:max="df.maxvalue"
|
||||
:min="df.minvalue"
|
||||
@blur="(e) => !isReadOnly && triggerChange(e.target.value)"
|
||||
@ -32,6 +33,7 @@ export default {
|
||||
name: 'Base',
|
||||
props: {
|
||||
df: Object,
|
||||
step: { type: Number, default: 1 },
|
||||
value: [String, Number, Boolean, Object],
|
||||
inputClass: [Function, String, Object],
|
||||
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>
|
||||
<!-- Template Builder Body -->
|
||||
<div
|
||||
class="w-full h-full bg-gray-25 grid"
|
||||
style="grid-template-columns: auto var(--w-quick-edit)"
|
||||
class="w-full overflowauto bg-gray-25 grid"
|
||||
style="
|
||||
grid-template-columns: auto var(--w-quick-edit);
|
||||
height: calc(100vh - var(--h-row-largest) - 1px);
|
||||
"
|
||||
v-if="doc"
|
||||
>
|
||||
<!-- Print View Container -->
|
||||
<div class="overflow-auto custom-scroll">
|
||||
<!-- Template Display Area -->
|
||||
<div class="overflow-auto custom-scroll p-4">
|
||||
<!-- 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 }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="doc.template && values && !helperText"
|
||||
ref="printContainer"
|
||||
class="h-full shadow-lg border bg-white"
|
||||
style="
|
||||
width: 21cm;
|
||||
height: 29.7cm;
|
||||
transform: scale(0.65);
|
||||
margin-top: -150px;
|
||||
margin-left: -100px;
|
||||
"
|
||||
<!-- Template Container -->
|
||||
<ScaledContainer
|
||||
v-if="doc.template && values"
|
||||
:scale="Math.max(scale, 0.1)"
|
||||
ref="scaledContainer"
|
||||
class="mx-auto shadow-lg border"
|
||||
>
|
||||
<!-- Template -->
|
||||
<component
|
||||
class="flex-1"
|
||||
class="flex-1 bg-white"
|
||||
:doc="values.doc"
|
||||
:print="values.print"
|
||||
:is="{ template: doc.template, props: ['doc', 'print'] }"
|
||||
/>
|
||||
</div>
|
||||
</ScaledContainer>
|
||||
</div>
|
||||
|
||||
<!-- 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 -->
|
||||
<div class="p-4 flex flex-col gap-4">
|
||||
<FormControl
|
||||
@ -62,7 +72,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Controls -->
|
||||
<!-- Controls Section -->
|
||||
<div class="p-4 border-t">
|
||||
<div
|
||||
class="flex justify-between items-center cursor-pointer select-none"
|
||||
@ -99,18 +109,25 @@
|
||||
/>
|
||||
|
||||
<FormControl
|
||||
v-if="doc.isCustom"
|
||||
v-if="displayDoc && doc.template"
|
||||
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"
|
||||
:border="true"
|
||||
:read-only="true"
|
||||
:value="doc.get('isCustom')"
|
||||
:value="scale"
|
||||
@change="(value: number) => scale = value"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Template -->
|
||||
<!-- Template Section -->
|
||||
<div class="p-4 border-t" v-if="doc.type">
|
||||
<div
|
||||
class="flex justify-between items-center cursor-pointer select-none"
|
||||
@ -125,7 +142,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Template Container -->
|
||||
<!-- Template Editor -->
|
||||
<textarea
|
||||
v-if="!templateCollapsed"
|
||||
style="
|
||||
@ -197,6 +214,7 @@ import {
|
||||
import { getActionsForDoc, getDocFromNameIfExistsElseNew } from 'src/utils/ui';
|
||||
import { getMapFromList } from 'utils/index';
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import ScaledContainer from './ScaledContainer.vue';
|
||||
import TemplateBuilderHint from './TemplateBuilderHint.vue';
|
||||
|
||||
export default defineComponent({
|
||||
@ -209,6 +227,7 @@ export default defineComponent({
|
||||
FormHeader,
|
||||
TemplateBuilderHint,
|
||||
DropdownWithActions,
|
||||
ScaledContainer,
|
||||
},
|
||||
provide() {
|
||||
return { doc: computed(() => this.doc) };
|
||||
@ -222,6 +241,7 @@ export default defineComponent({
|
||||
templateCollapsed: false,
|
||||
helpersCollapsed: true,
|
||||
displayDoc: null,
|
||||
scale: 0.65,
|
||||
} as {
|
||||
hint: null | Record<string, unknown>;
|
||||
values: null | Record<string, unknown>;
|
||||
@ -230,6 +250,7 @@ export default defineComponent({
|
||||
displayDoc: PrintTemplate | null;
|
||||
templateCollapsed: boolean;
|
||||
helpersCollapsed: boolean;
|
||||
scale: number;
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
@ -239,20 +260,11 @@ export default defineComponent({
|
||||
this.helpersCollapsed = false;
|
||||
}
|
||||
|
||||
if (!this.fyo.store.isDevelopment) {
|
||||
return;
|
||||
if (this.fyo.store.isDevelopment) {
|
||||
// @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: {
|
||||
async makePDF() {
|
||||
@ -261,7 +273,12 @@ export default defineComponent({
|
||||
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);
|
||||
},
|
||||
async sync() {
|
||||
|
Loading…
Reference in New Issue
Block a user