mirror of
https://github.com/frappe/books.git
synced 2025-01-23 15:18:24 +00:00
Merge pull request #398 from 18alantom/v1-design-update
incr: V1 design update
This commit is contained in:
commit
ba64186d01
4
main.ts
4
main.ts
@ -26,7 +26,7 @@ export class Main {
|
||||
mainWindow: BrowserWindow | null = null;
|
||||
|
||||
WIDTH = 1200;
|
||||
HEIGHT = process.platform === 'win32' ? 926 : 900;
|
||||
HEIGHT = process.platform === 'win32' ? 826 : 800;
|
||||
|
||||
constructor() {
|
||||
this.icon = this.isDevelopment
|
||||
@ -77,8 +77,6 @@ export class Main {
|
||||
const options: BrowserWindowConstructorOptions = {
|
||||
width: this.WIDTH,
|
||||
height: this.HEIGHT,
|
||||
minWidth: this.WIDTH,
|
||||
minHeight: this.HEIGHT,
|
||||
title: this.title,
|
||||
titleBarStyle: 'hidden',
|
||||
trafficLightPosition: { x: 16, y: 16 },
|
||||
|
@ -1,7 +1,14 @@
|
||||
<template>
|
||||
<button
|
||||
class="focus:outline-none rounded-md shadow-button flex-center h-8"
|
||||
:style="style"
|
||||
class="
|
||||
focus:outline-none
|
||||
rounded-md
|
||||
flex
|
||||
justify-center
|
||||
items-center
|
||||
h-8
|
||||
text-sm
|
||||
"
|
||||
:class="_class"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
@ -30,21 +37,15 @@ export default {
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
return {
|
||||
...(this.padding
|
||||
? { padding: this.icon ? '6px 12px' : '6px 24px' }
|
||||
: {}),
|
||||
color: this.type === 'primary' ? '#fff' : '#112B42',
|
||||
'background-image':
|
||||
this.type === 'primary'
|
||||
? 'linear-gradient(180deg, #2C9AF1 0%, #2490EF 100%)'
|
||||
: 'linear-gradient(180deg, #F9F9FA 0%, #F4F4F6 100%)',
|
||||
};
|
||||
},
|
||||
_class() {
|
||||
return {
|
||||
'opacity-50 cursor-not-allowed pointer-events-none': this.disabled,
|
||||
'text-white': this.type === 'primary',
|
||||
'bg-blue-500': this.type === 'primary',
|
||||
'text-gray-900': this.type !== 'primary',
|
||||
'bg-gray-100': this.type !== 'primary',
|
||||
'px-3': this.padding && this.icon,
|
||||
'px-6': this.padding && !this.icon,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -357,6 +357,6 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
rect:hover {
|
||||
filter: brightness(115%);
|
||||
filter: brightness(105%);
|
||||
}
|
||||
</style>
|
||||
|
@ -53,16 +53,12 @@
|
||||
@mouseover="$emit('change', i)"
|
||||
/>
|
||||
</template>
|
||||
</svg>
|
||||
<div
|
||||
class="text-center w-28 relative"
|
||||
:style="{
|
||||
top: `calc(-50% + ${textOffsetY}px)`,
|
||||
left: `calc(50% + ${textOffsetX}px)`,
|
||||
transform: 'translateX(-50%)',
|
||||
}"
|
||||
>
|
||||
<p class="text-base font-bold whitespace-nowrap">
|
||||
<text
|
||||
:x="cx"
|
||||
:y="cy"
|
||||
text-anchor="middle"
|
||||
style="font-size: 6px; font-weight: bold; fill: #415668"
|
||||
>
|
||||
{{
|
||||
valueFormatter(
|
||||
active !== null && sectors.length !== 0
|
||||
@ -71,23 +67,20 @@
|
||||
'Currency'
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<p
|
||||
class="
|
||||
text-xs text-gray-600
|
||||
font-semibold
|
||||
whitespace-nowrap
|
||||
overflow-x-auto
|
||||
no-scrollbar
|
||||
"
|
||||
</text>
|
||||
<text
|
||||
:x="cx"
|
||||
:y="cy + 8"
|
||||
text-anchor="middle"
|
||||
style="font-size: 5px; fill: #a1abb4"
|
||||
>
|
||||
{{
|
||||
active !== null && sectors.length !== 0
|
||||
? sectors[active].label
|
||||
: totalLabel
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</text>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -5,16 +5,21 @@
|
||||
</div>
|
||||
|
||||
<!-- Title Row -->
|
||||
<Row :ratio="ratio" class="border-b px-2 text-gray-600 w-full">
|
||||
<Row
|
||||
:ratio="ratio"
|
||||
class="border-b px-2 text-gray-600 w-full flex items-center"
|
||||
>
|
||||
<div class="flex items-center pl-2">#</div>
|
||||
<div
|
||||
class="items-center flex px-2 h-row-mid"
|
||||
:class="{
|
||||
'px-2 py-3': size === 'small',
|
||||
'px-3 py-4': size !== 'small',
|
||||
'text-right': isNumeric(df),
|
||||
'ml-auto': isNumeric(df),
|
||||
}"
|
||||
v-for="df in tableFields"
|
||||
:key="df.fieldname"
|
||||
:style="{
|
||||
height: ``,
|
||||
}"
|
||||
>
|
||||
{{ df.label }}
|
||||
</div>
|
||||
@ -40,29 +45,28 @@
|
||||
<!-- Add Row and Row Count -->
|
||||
<Row
|
||||
:ratio="ratio"
|
||||
class="text-gray-500 cursor-pointer border-transparent px-2 w-full"
|
||||
class="
|
||||
text-gray-500
|
||||
cursor-pointer
|
||||
border-transparent
|
||||
px-2
|
||||
w-full
|
||||
h-row-mid
|
||||
flex
|
||||
items-center
|
||||
"
|
||||
v-if="!isReadOnly"
|
||||
@click="addRow"
|
||||
>
|
||||
<div class="flex items-center pl-1">
|
||||
<feather-icon name="plus" class="w-4 h-4 text-gray-500" />
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-between"
|
||||
:class="{
|
||||
'px-2 py-3': size === 'small',
|
||||
'px-3 py-4': size !== 'small',
|
||||
}"
|
||||
>
|
||||
<div class="flex justify-between px-2">
|
||||
{{ t`Add Row` }}
|
||||
</div>
|
||||
<div v-for="i in ratio.slice(3).length" :key="i"></div>
|
||||
<div
|
||||
class="text-right"
|
||||
:class="{
|
||||
'px-2 py-3': size === 'small',
|
||||
'px-3 py-4': size !== 'small',
|
||||
}"
|
||||
class="text-right px-2"
|
||||
v-if="
|
||||
value && maxRowsBeforeOverflow && value.length > maxRowsBeforeOverflow
|
||||
"
|
||||
@ -161,6 +165,11 @@ export default {
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
height() {
|
||||
if (this.size === 'small') {
|
||||
}
|
||||
return 2;
|
||||
},
|
||||
ratio() {
|
||||
return [0.3].concat(this.tableFields.map(() => 1));
|
||||
},
|
||||
|
@ -1,5 +1,18 @@
|
||||
<template>
|
||||
<Row :ratio="ratio" class="w-full px-2 border-b hover:bg-brand-100 group">
|
||||
<Row
|
||||
:ratio="ratio"
|
||||
class="
|
||||
w-full
|
||||
px-2
|
||||
border-b
|
||||
hover:bg-gray-50
|
||||
h-row-mid
|
||||
group
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
"
|
||||
>
|
||||
<!-- Index or Remove button -->
|
||||
<div class="flex items-center pl-2 text-gray-600">
|
||||
<span class="hidden group-hover:inline-block">
|
||||
@ -18,7 +31,6 @@
|
||||
<FormControl
|
||||
v-for="df in tableFields"
|
||||
:size="size"
|
||||
class="py-2"
|
||||
:read-only="readOnly"
|
||||
:input-class="{ 'text-right': isNumeric(df), 'bg-transparent': true }"
|
||||
:key="df.fieldname"
|
||||
|
@ -7,12 +7,7 @@
|
||||
right
|
||||
>
|
||||
<template v-slot="{ toggleDropdown }">
|
||||
<Button
|
||||
class="text-gray-900"
|
||||
:type="type"
|
||||
:icon="true"
|
||||
@click="toggleDropdown()"
|
||||
>
|
||||
<Button :type="type" :icon="icon" @click="toggleDropdown()">
|
||||
<slot>
|
||||
<feather-icon name="more-horizontal" class="w-4 h-4" />
|
||||
</slot>
|
||||
@ -30,6 +25,7 @@ export default {
|
||||
props: {
|
||||
actions: { default: [] },
|
||||
type: { type: String, default: 'secondary' },
|
||||
icon: { type: Boolean, default: true },
|
||||
},
|
||||
inject: {
|
||||
doc: { default: null },
|
||||
|
@ -4,7 +4,7 @@
|
||||
<Button :icon="true" @click="togglePopover()">
|
||||
<span class="flex items-center">
|
||||
<Icon name="filter" size="12" class="stroke-current text-gray-800" />
|
||||
<span class="ml-2 text-base text-black">
|
||||
<span class="ml-1">
|
||||
<template v-if="activeFilterCount > 0">
|
||||
{{ filterAppliedMessage }}
|
||||
</template>
|
||||
|
35
src/components/FormContainer.vue
Normal file
35
src/components/FormContainer.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="flex flex-col bg-gray-25">
|
||||
<!-- Page Header (Title, Buttons, etc) -->
|
||||
<PageHeader :backLink="backLink" :title="title" :border="false">
|
||||
<slot name="header" />
|
||||
</PageHeader>
|
||||
|
||||
<!-- Invoice Form -->
|
||||
<div
|
||||
class="
|
||||
border
|
||||
rounded-lg
|
||||
shadow-lg
|
||||
flex flex-col
|
||||
self-center
|
||||
w-form
|
||||
h-full
|
||||
mb-4
|
||||
bg-white
|
||||
"
|
||||
>
|
||||
<slot name="body" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import PageHeader from './PageHeader.vue';
|
||||
export default {
|
||||
components: { PageHeader },
|
||||
props: {
|
||||
backLink: { type: Boolean, default: false },
|
||||
title: { type: String, default: '' },
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,14 +1,16 @@
|
||||
<script>
|
||||
import { uicolors } from 'src/utils/colors';
|
||||
|
||||
export default {
|
||||
name: 'IconBase',
|
||||
props: ['active'],
|
||||
computed: {
|
||||
lightColor() {
|
||||
return this.active ? '#8CC0F1' : '#A1ABB4';
|
||||
return this.active ? uicolors.blue['300'] : uicolors.gray['400'];
|
||||
},
|
||||
darkColor() {
|
||||
return this.active ? '#4794E9' : '#415668';
|
||||
}
|
||||
}
|
||||
return this.active ? uicolors.blue['500'] : uicolors.gray['700'];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,12 +1,23 @@
|
||||
<template>
|
||||
<div class="my-4 mx-4 flex justify-between window-drag">
|
||||
<h1 class="text-2xl font-bold select-none" v-if="title && !backLink">
|
||||
<div
|
||||
class="
|
||||
px-4
|
||||
flex
|
||||
justify-between
|
||||
window-drag
|
||||
items-center
|
||||
h-row-largest
|
||||
flex-shrink-0
|
||||
"
|
||||
:class="border ? 'border-b' : ''"
|
||||
>
|
||||
<h1 class="text-xl font-semibold select-none" v-if="title && !backLink">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<BackLink v-if="backLink" class="window-no-drag"/>
|
||||
<BackLink v-if="backLink" class="window-no-drag" />
|
||||
<div class="flex items-stretch window-no-drag gap-2">
|
||||
<slot />
|
||||
<SearchBar v-if="!hideSearch"/>
|
||||
<SearchBar v-if="!hideSearch" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -19,6 +30,7 @@ export default {
|
||||
title: { type: String, default: '' },
|
||||
backLink: { type: Boolean, default: false },
|
||||
hideSearch: { type: Boolean, default: false },
|
||||
border: { type: Boolean, default: true },
|
||||
},
|
||||
components: { SearchBar, BackLink },
|
||||
};
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div class="my-3 grid grid-cols-3 text-gray-800 text-sm select-none">
|
||||
<div
|
||||
class="grid grid-cols-3 text-gray-800 text-sm select-none items-center"
|
||||
style="height: 50px"
|
||||
>
|
||||
<!-- Length Display -->
|
||||
<div class="justify-self-start">
|
||||
{{
|
||||
|
@ -1,93 +0,0 @@
|
||||
<template>
|
||||
<div id="importWizard" class="modal-body" style="overflow: hidden;">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<!-- <div v-for="(entry, i) in entries" :key="i">{{ entry['Date'] }}</div> -->
|
||||
<table class="table table-sm">
|
||||
<thead style="font-size: 13px">
|
||||
<tr>
|
||||
<th scope="col">
|
||||
<input type="checkbox" checked="true" ref="all" @change="allSelected" />
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
v-for="(fieldname, index) in Object.keys(entries[0])"
|
||||
:key="index"
|
||||
>{{ fieldname }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody style="font-size: 13px">
|
||||
<tr v-for="(entry, index) in entries" :key="index">
|
||||
<th scope="row">
|
||||
<input type="checkbox" checked="true" :ref="'cb-'+index" @change="rowSelected" />
|
||||
</th>
|
||||
<td v-for="(fieldname, idx) in Object.keys(entry)" :key="idx">{{ entry[fieldname] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 text-right">
|
||||
<f-button primary @click="reconcile">{{ 'Reconcile' }}</f-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import luxon from 'luxon';
|
||||
import { fyo } from 'src/initFyo';
|
||||
|
||||
export default {
|
||||
props: ['entries', 'afterReconcile'],
|
||||
data() {
|
||||
return {
|
||||
selectedEntries: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
allSelected() {
|
||||
for (let i = 0; i < this.entries.length; i++) {
|
||||
this.$refs['cb-' + i][0].checked = this.$refs['all'].checked;
|
||||
}
|
||||
},
|
||||
rowSelected() {
|
||||
for (let i = 0; i < this.entries.length; i++) {
|
||||
if (!this.$refs['cb-' + i][0].checked) {
|
||||
this.$refs['all'].checked = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$modal.hide();
|
||||
},
|
||||
async reconcile() {
|
||||
for (let i = 0; i < this.entries.length; i++) {
|
||||
if (this.$refs['cb-' + i][0].checked)
|
||||
this.selectedEntries.push(this.entries[i]);
|
||||
}
|
||||
for (let entry of this.selectedEntries) {
|
||||
const payment = await fyo.doc.getDoc('Payment', entry['Payment Entry']);
|
||||
const clearanceDate =
|
||||
luxon.DateTime.fromFormat(
|
||||
entry['Clearance Date'],
|
||||
'dd/MM/yy'
|
||||
).toISO() ||
|
||||
luxon.DateTime.fromFormat(
|
||||
entry['Clearance Date'],
|
||||
'dd/MM/yyyy'
|
||||
).toISO();
|
||||
payment.set({ clearanceDate });
|
||||
await payment.sync();
|
||||
}
|
||||
this.close();
|
||||
await this.afterReconcile();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.modal-dialog {
|
||||
max-width: 600px !important;
|
||||
}
|
||||
</style>
|
@ -4,9 +4,12 @@
|
||||
<div class="overflow-hidden" v-if="dataSlice.length">
|
||||
<!--Title Row -->
|
||||
<div
|
||||
class="w-full overflow-x-hidden flex items-center border-b"
|
||||
class="w-full overflow-x-hidden flex items-center border-b px-4"
|
||||
ref="titlerow"
|
||||
:style="{ height: `${hconst}px`, paddingRight: '8px' }"
|
||||
:style="{
|
||||
height: `${hconst}px`,
|
||||
paddingRight: 'calc(var(--w-scrollbar) + 1rem)',
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-for="(col, c) in report.columns"
|
||||
@ -33,11 +36,14 @@
|
||||
<template v-for="(row, r) in dataSlice" :key="r + '-row'">
|
||||
<div
|
||||
v-if="!row.folded"
|
||||
class="flex items-center w-max"
|
||||
:style="{ height: `${hconst}px` }"
|
||||
class="flex items-center w-max px-4"
|
||||
:style="{
|
||||
height: `${hconst}px`,
|
||||
minWidth: `calc(var(--w-desk) - var(--w-scrollbar))`,
|
||||
}"
|
||||
:class="[
|
||||
r !== pageEnd - 1 ? 'border-b' : '',
|
||||
row.isGroup ? 'hover:bg-gray-100 cursor-pointer' : '',
|
||||
row.isGroup ? 'hover:bg-gray-50 cursor-pointer' : '',
|
||||
]"
|
||||
@click="() => onRowClick(row, r)"
|
||||
>
|
||||
@ -70,6 +76,7 @@
|
||||
<hr />
|
||||
<Paginator
|
||||
:item-count="report?.reportData?.length ?? 0"
|
||||
class="px-4"
|
||||
@index-change="setPageIndices"
|
||||
/>
|
||||
</div>
|
||||
@ -140,7 +147,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
if (cell.italics) {
|
||||
styles['font-style'] = 'italic';
|
||||
styles['font-style'] = 'oblique 15deg';
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
|
@ -1,29 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- Search Bar Button -->
|
||||
<button
|
||||
@click="open"
|
||||
class="
|
||||
focus:outline-none
|
||||
shadow-button
|
||||
flex flex-row
|
||||
gap-1
|
||||
text-base text-gray-700
|
||||
bg-gray-100
|
||||
rounded-md
|
||||
h-8
|
||||
w-48
|
||||
px-3
|
||||
items-center
|
||||
hover:bg-gray-200
|
||||
"
|
||||
>
|
||||
<feather-icon name="search" class="w-4 h-4" />
|
||||
<Button @click="open" class="px-2" :padding="false">
|
||||
<feather-icon name="search" class="w-4 h-4 mr-1 text-gray-800" />
|
||||
<p>{{ t`Search` }}</p>
|
||||
<div class="text-gray-400 ml-auto text-sm">
|
||||
<div class="text-gray-500 px-1 ml-4 text-sm">
|
||||
{{ modKey('k') }}
|
||||
</div>
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- Search Modal -->
|
||||
@ -71,7 +55,7 @@
|
||||
<div
|
||||
v-if="si.group === 'Docs'"
|
||||
class="flex w-full justify-between px-3 items-center"
|
||||
style="height: 48px; margin-left: -2px"
|
||||
style="height: var(--h-row-mid); margin-left: -2px"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<p class="text-gray-900">
|
||||
@ -93,7 +77,7 @@
|
||||
<div
|
||||
v-else
|
||||
class="flex flex-row w-full justify-between px-3 items-center"
|
||||
style="height: 48px; margin-left: -2px"
|
||||
style="height: var(--h-row-mid); margin-left: -2px"
|
||||
>
|
||||
<p class="text-gray-900">
|
||||
{{ si.label }}
|
||||
@ -126,7 +110,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="hover:bg-gray-100 px-2 py-0.5 rounded text-gray-800"
|
||||
class="hover:bg-gray-50 px-2 py-0.5 rounded text-gray-800"
|
||||
@click="showMore = !showMore"
|
||||
>
|
||||
{{ showMore ? t`Less Filters` : t`More Filters` }}
|
||||
@ -215,6 +199,7 @@ import { getGroupLabelMap, searchGroups } from 'src/utils/search';
|
||||
import { useKeys } from 'src/utils/vueUtils';
|
||||
import { getIsNullOrUndef } from 'utils/';
|
||||
import { nextTick, watch } from 'vue';
|
||||
import Button from './Button.vue';
|
||||
import Modal from './Modal.vue';
|
||||
|
||||
export default {
|
||||
@ -234,7 +219,7 @@ export default {
|
||||
};
|
||||
},
|
||||
inject: ['searcher'],
|
||||
components: { Modal },
|
||||
components: { Modal, Button },
|
||||
async mounted() {
|
||||
if (fyo.store.isDevelopment) {
|
||||
window.search = this;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="p-2 h-full flex justify-between flex-col bg-gray-100"
|
||||
class="p-2 h-full flex justify-between flex-col bg-gray-25"
|
||||
:class="{
|
||||
'window-drag': platform !== 'Windows',
|
||||
}"
|
||||
@ -13,30 +13,15 @@
|
||||
>
|
||||
<h6
|
||||
class="
|
||||
text-xl
|
||||
font-semibold
|
||||
whitespace-nowrap
|
||||
overflow-auto
|
||||
no-scrollbar
|
||||
select-none
|
||||
w-32
|
||||
"
|
||||
>
|
||||
{{ companyName }}
|
||||
</h6>
|
||||
<feather-icon
|
||||
class="
|
||||
w-5
|
||||
h-5
|
||||
ml-1
|
||||
stroke-2
|
||||
cursor-pointer
|
||||
text-gray-600
|
||||
hover:text-gray-800
|
||||
"
|
||||
name="chevron-down"
|
||||
@click="$emit('change-db-file')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Items -->
|
||||
@ -49,9 +34,9 @@
|
||||
items-center
|
||||
rounded-md
|
||||
cursor-pointer
|
||||
hover:bg-white
|
||||
hover:bg-gray-100
|
||||
"
|
||||
:class="isActiveGroup(group) && !group.items ? 'bg-white' : ''"
|
||||
:class="isActiveGroup(group) && !group.items ? 'bg-gray-100' : ''"
|
||||
@click="onGroupClick(group)"
|
||||
>
|
||||
<Icon
|
||||
@ -81,7 +66,7 @@
|
||||
pl-10
|
||||
rounded
|
||||
cursor-pointer
|
||||
hover:bg-white
|
||||
hover:bg-gray-100
|
||||
"
|
||||
:class="itemActiveClass(item)"
|
||||
@click="onItemClick(item)"
|
||||
@ -93,17 +78,42 @@
|
||||
</div>
|
||||
|
||||
<!-- Report Issue and App Version -->
|
||||
<div class="px-5 window-no-drag">
|
||||
<p v-if="fyo.store.isDevelopment" class="text-sm text-gray-600">
|
||||
Development
|
||||
</p>
|
||||
<div class="window-no-drag flex flex-col gap-2 p-2">
|
||||
<button
|
||||
class="pb-1 text-sm text-gray-600 hover:text-gray-800 w-full text-left"
|
||||
class="
|
||||
flex
|
||||
text-sm text-gray-600
|
||||
hover:text-gray-800
|
||||
gap-1
|
||||
items-center
|
||||
"
|
||||
@click="() => reportIssue()"
|
||||
>
|
||||
{{ t`Report Issue` }}
|
||||
<feather-icon name="flag" class="h-4 w-4" />
|
||||
<p>
|
||||
{{ t`Report Issue` }}
|
||||
</p>
|
||||
</button>
|
||||
<p class="pb-3 text-sm text-gray-600 select-none">v{{ appVersion }}</p>
|
||||
|
||||
<button
|
||||
class="
|
||||
flex
|
||||
text-sm text-gray-600
|
||||
hover:text-gray-800
|
||||
gap-1
|
||||
items-center
|
||||
"
|
||||
@click="$emit('change-db-file')"
|
||||
>
|
||||
<feather-icon name="database" class="h-4 w-4" />
|
||||
<p>{{ t`Change DB` }}</p>
|
||||
</button>
|
||||
<p
|
||||
v-if="fyo.store.isDevelopment"
|
||||
class="text-xs text-gray-500 select-none"
|
||||
>
|
||||
dev mode
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -179,7 +189,7 @@ export default {
|
||||
let routeMatch = currentRoute === item.route;
|
||||
let schemaNameMatch =
|
||||
item.schemaName && params.schemaName === item.schemaName;
|
||||
return routeMatch || schemaNameMatch ? 'bg-white text-blue-500' : '';
|
||||
return routeMatch || schemaNameMatch ? 'bg-gray-100 text-blue-500' : '';
|
||||
},
|
||||
isActiveGroup(group) {
|
||||
return this.activeGroup && group.label === this.activeGroup.label;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Badge class="text-xs flex-center px-3 ml-2" :color="color" v-if="status">{{
|
||||
<Badge class="text-sm flex-center px-3 ml-2" :color="color" v-if="status">{{
|
||||
statusLabel
|
||||
}}</Badge>
|
||||
</template>
|
||||
|
@ -20,6 +20,8 @@
|
||||
:key="`${df.fieldname}-inline`"
|
||||
>
|
||||
<TwoColumnForm
|
||||
class="overflow-auto"
|
||||
style="max-height: calc((var(--h-row-mid) + 1px) * 3 - 1px)"
|
||||
ref="inlineEditForm"
|
||||
:doc="inlineEditDoc"
|
||||
:fields="getInlineEditFields(df)"
|
||||
@ -29,13 +31,16 @@
|
||||
:autosave="false"
|
||||
@error="(msg) => $emit('error', msg)"
|
||||
/>
|
||||
<div class="flex px-4 pb-2 gap-2">
|
||||
<Button class="w-1/2 text-gray-900" @click="stopInlineEditing">
|
||||
<div
|
||||
class="flex px-4 py-4 justify-between items-center"
|
||||
style="max-height: calc(var(--h-row-mid) + 1px)"
|
||||
>
|
||||
<Button class="text-gray-900 w-20" @click="stopInlineEditing">
|
||||
{{ t`Cancel` }}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
class="w-1/2 text-white"
|
||||
class="text-white w-20"
|
||||
@click="saveInlineEditDoc(df)"
|
||||
>
|
||||
{{ t`Save` }}
|
||||
@ -49,12 +54,13 @@
|
||||
class="grid items-center"
|
||||
:class="{
|
||||
'border-b': !noBorder,
|
||||
'h-12':
|
||||
!['AttachImage', 'Text'].includes(df.fieldtype) &&
|
||||
!errors[df.fieldname],
|
||||
}"
|
||||
:key="`${df.fieldname}-regular`"
|
||||
:style="style"
|
||||
:style="{
|
||||
...style,
|
||||
|
||||
height: getFieldHeight(df),
|
||||
}"
|
||||
>
|
||||
<div class="py-2 pl-4 flex text-gray-600">
|
||||
<div class="py-1">
|
||||
@ -76,6 +82,7 @@
|
||||
:value="getRegularValue(df)"
|
||||
:class="{ 'p-2': df.fieldtype === 'Check' }"
|
||||
:read-only="evaluateReadOnly(df)"
|
||||
input-class="bg-transparent"
|
||||
@change="async (value) => await onChange(df, value)"
|
||||
@focus="activateInlineEditing(df)"
|
||||
@new-doc="async (newdoc) => await onChange(df, newdoc.name)"
|
||||
@ -149,6 +156,17 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getFieldHeight(df) {
|
||||
if (['AttachImage', 'Text'].includes(df.fieldtype)) {
|
||||
return 'calc((var(--h-row-mid) + 1px) * 2)';
|
||||
}
|
||||
|
||||
if (this.errors[df.fieldname]) {
|
||||
return 'calc((var(--h-row-mid) + 1px) * 2)';
|
||||
}
|
||||
|
||||
return 'calc(var(--h-row-mid) + 1px)';
|
||||
},
|
||||
getRegularValue(df) {
|
||||
if (!df.inline) {
|
||||
return this.doc[df.fieldname];
|
||||
|
@ -1,12 +1,21 @@
|
||||
<template>
|
||||
<div class="py-4" v-if="pendingInvoices.length">
|
||||
<div class="px-4 text-sm text-gray-600">
|
||||
<div v-if="pendingInvoices.length">
|
||||
<div
|
||||
class="
|
||||
px-4
|
||||
text-sm text-gray-600
|
||||
border-b
|
||||
flex
|
||||
items-center
|
||||
h-row-smallest
|
||||
"
|
||||
>
|
||||
{{ t`Recent Invoices` }}
|
||||
</div>
|
||||
|
||||
<!-- Invoice List -->
|
||||
<div
|
||||
class="px-4 py-3 border-b hover:bg-gray-100 cursor-pointer text-base"
|
||||
class="px-4 py-4 border-b hover:bg-gray-50 cursor-pointer text-base"
|
||||
v-for="invoice in pendingInvoices"
|
||||
:key="invoice.name"
|
||||
@click="routeToForm(invoice)"
|
||||
@ -22,13 +31,13 @@
|
||||
</div>
|
||||
|
||||
<!-- Invoice Date & Amount -->
|
||||
<div class="flex justify-between">
|
||||
<div class="flex justify-between text-gray-900">
|
||||
<span>
|
||||
{{ fyo.format(invoice.date, getInvoiceField(invoice, 'date')) }}
|
||||
</span>
|
||||
<div>
|
||||
<!-- Paid Amount -->
|
||||
<span class="font-medium text-gray-900">
|
||||
<span>
|
||||
{{
|
||||
fyo.format(
|
||||
amountPaid(invoice),
|
||||
@ -38,7 +47,7 @@
|
||||
</span>
|
||||
|
||||
<!-- Outstanding Amount -->
|
||||
<span class="text-gray-600" v-if="!fullyPaid(invoice)">
|
||||
<span class="text-gray-600 font-medium" v-if="!fullyPaid(invoice)">
|
||||
({{
|
||||
fyo.format(
|
||||
invoice.outstandingAmount,
|
||||
|
@ -25,8 +25,8 @@ export default {
|
||||
|
||||
<style>
|
||||
.scroll-container::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
width: var(--w-scrollbar);
|
||||
height: var(--w-scrollbar);
|
||||
}
|
||||
.scroll-container::-webkit-scrollbar-thumb {
|
||||
background-color: theme('colors.gray.100');
|
||||
|
@ -3,31 +3,33 @@
|
||||
<PageHeader :title="t`Chart of Accounts`" />
|
||||
|
||||
<!-- Chart of Accounts -->
|
||||
<div class="flex-1 flex flex-col mx-4 overflow-y-auto mb-4" v-if="root">
|
||||
<div class="flex-1 flex flex-col overflow-y-auto mb-4" v-if="root">
|
||||
<!-- Chart of Accounts Indented List -->
|
||||
<template v-for="account in allAccounts" :key="account.name">
|
||||
<!-- Account List Item -->
|
||||
<div
|
||||
class="
|
||||
mt-2
|
||||
py-2
|
||||
cursor-pointer
|
||||
hover:bg-gray-100
|
||||
hover:bg-gray-50
|
||||
group
|
||||
flex
|
||||
items-center
|
||||
border-b
|
||||
flex-shrink-0
|
||||
pr-4
|
||||
"
|
||||
:class="[
|
||||
account.level !== 0 ? 'text-base' : 'text-lg',
|
||||
isQuickEditOpen(account) ? 'bg-gray-200' : '',
|
||||
`pl-${account.level * 8}`,
|
||||
]"
|
||||
:style="`height: calc(var(--h-row-mid) + 1px); padding-left: calc(1rem + 2rem * ${account.level})`"
|
||||
@click="onClick(account)"
|
||||
>
|
||||
<component :is="getIconComponent(account)" class="ml-2" />
|
||||
<component :is="getIconComponent(account)" />
|
||||
<div class="flex items-baseline">
|
||||
<div
|
||||
class="ml-3"
|
||||
class="ml-4"
|
||||
:class="[!account.parentAccount && 'font-semibold']"
|
||||
>
|
||||
{{ account.name }}
|
||||
@ -69,25 +71,24 @@
|
||||
<div
|
||||
v-if="account.addingAccount || account.addingGroupAccount"
|
||||
class="
|
||||
mt-2
|
||||
px-4
|
||||
py-2
|
||||
border-b
|
||||
cursor-pointer
|
||||
hover:bg-gray-100
|
||||
rounded-md
|
||||
hover:bg-gray-50
|
||||
group
|
||||
flex
|
||||
items-center
|
||||
text-base
|
||||
"
|
||||
:class="`${account.level !== 0 ? 'text-base' : 'text-lg'} pl-${
|
||||
(account.level + 1) * 8
|
||||
}`"
|
||||
:style="`height: calc(var(--h-row-mid) + 1px); padding-left: calc(1rem + 2rem * ${
|
||||
account.level + 1
|
||||
})`"
|
||||
:key="account.name + '-adding-account'"
|
||||
>
|
||||
<component
|
||||
:is="getIconComponent({ isGroup: account.addingGroupAccount })"
|
||||
/>
|
||||
<div class="flex items-baseline ml-3">
|
||||
<div class="flex ml-4 h-row-mid items-center">
|
||||
<input
|
||||
class="focus:outline-none bg-transparent"
|
||||
:class="{ 'text-gray-600': insertingAccount }"
|
||||
|
@ -2,17 +2,17 @@
|
||||
<div>
|
||||
<!-- Title and Period Selector -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="font-medium">{{ t`Cashflow` }}</div>
|
||||
<div class="font-medium text-base">{{ t`Cashflow` }}</div>
|
||||
|
||||
<!-- Chart Legend -->
|
||||
<div class="flex text-base" v-if="hasData">
|
||||
<div class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-sm inline-block bg-blue-500"></span>
|
||||
<span class="ml-2 text-gray-900">{{ t`Inflow` }}</span>
|
||||
<div class="flex text-base gap-8" v-if="hasData">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-3 h-3 rounded-sm inline-block bg-blue-500" />
|
||||
<span class="text-gray-900">{{ t`Inflow` }}</span>
|
||||
</div>
|
||||
<div class="flex items-center ml-6">
|
||||
<span class="w-3 h-3 rounded-sm inline-block bg-gray-500"></span>
|
||||
<span class="ml-2 text-gray-900">{{ t`Outflow` }}</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-3 h-3 rounded-sm inline-block bg-pink-500" />
|
||||
<span class="text-gray-900">{{ t`Outflow` }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="w-16 h-5 bg-gray-200 rounded" />
|
||||
@ -28,7 +28,9 @@
|
||||
|
||||
<!-- Line Chart -->
|
||||
<LineChart
|
||||
class="mt-4"
|
||||
v-if="chartData.points.length"
|
||||
:aspect-ratio="4.15"
|
||||
:colors="chartData.colors"
|
||||
:points="chartData.points"
|
||||
:x-labels="chartData.xLabels"
|
||||
@ -46,6 +48,7 @@ import { ModelNameEnum } from 'models/types';
|
||||
import LineChart from 'src/components/Charts/LineChart.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { formatXLabels, getYMax } from 'src/utils/chart';
|
||||
import { uicolors } from 'src/utils/colors';
|
||||
import { getDatesAndPeriodList } from 'src/utils/misc';
|
||||
import { getMapFromList } from 'utils/';
|
||||
import PeriodSelector from './PeriodSelector';
|
||||
@ -74,10 +77,10 @@ export default {
|
||||
computed: {
|
||||
chartData() {
|
||||
let data = this.data;
|
||||
let colors = ['#2490EF', '#B7BFC6'];
|
||||
let colors = [uicolors.blue['500'], uicolors.pink['500']];
|
||||
if (!this.hasData) {
|
||||
data = dummyData;
|
||||
colors = ['#E9EBED', '#DFE1E2'];
|
||||
colors = [uicolors.gray['200'], uicolors.gray['100']];
|
||||
}
|
||||
|
||||
const xLabels = data.map((cf) => cf['yearmonth']);
|
||||
|
@ -1,15 +1,21 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<div class="overflow-hidden h-screen" style="width: var(--w-desk)">
|
||||
<PageHeader :title="t`Dashboard`" />
|
||||
|
||||
<div class="mx-4 overflow-y-auto no-scrollbar flex flex-col gap-8">
|
||||
<Cashflow class="" />
|
||||
<hr />
|
||||
<UnpaidInvoices />
|
||||
<hr />
|
||||
<div class="flex gap-8">
|
||||
<ProfitAndLoss class="w-full" />
|
||||
<Expenses class="w-full" />
|
||||
<div class="no-scrollbar overflow-auto h-full">
|
||||
<div
|
||||
style="min-width: var(--w-desk-fixed); min-height: var(--h-app)"
|
||||
class="overflow-auto"
|
||||
>
|
||||
<Cashflow class="p-4" />
|
||||
<hr />
|
||||
<UnpaidInvoices />
|
||||
<hr />
|
||||
<div class="flex">
|
||||
<ProfitAndLoss class="w-full p-4 border-r" />
|
||||
<Expenses class="w-full p-4" />
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6,9 +6,10 @@
|
||||
<PeriodSelector :value="period" @change="(value) => (period = value)" />
|
||||
</template>
|
||||
</SectionHeader>
|
||||
|
||||
<div class="flex relative" v-show="hasData">
|
||||
<!-- Chart Legend -->
|
||||
<div class="w-1/2 flex flex-col gap-5 mt-8">
|
||||
<div class="w-1/2 flex flex-col gap-4 justify-center">
|
||||
<!-- Ledgend Item -->
|
||||
<div
|
||||
class="flex items-center text-sm"
|
||||
@ -19,7 +20,7 @@
|
||||
>
|
||||
<div class="w-3 h-3 rounded-sm flex-shrink-0" :class="d.class" />
|
||||
<p class="ml-2 overflow-x-auto whitespace-nowrap no-scrollbar w-28">
|
||||
{{ d.account }}
|
||||
{{ d.account }}
|
||||
</p>
|
||||
<p class="whitespace-nowrap flex-shrink-0 ml-auto">
|
||||
{{ fyo.format(d?.total ?? 0, 'Currency') }}
|
||||
@ -27,11 +28,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<DonutChart
|
||||
class="w-1/2"
|
||||
class="w-1/2 my-auto"
|
||||
:active="active"
|
||||
:sectors="sectors"
|
||||
:offset-x="3"
|
||||
:thickness="11.5"
|
||||
:thickness="10"
|
||||
:text-offset-x="6.5"
|
||||
:value-formatter="(value) => fyo.format(value, 'Currency')"
|
||||
:total-label="t`Total Spending`"
|
||||
@ -52,8 +53,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { truncate } from 'lodash';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import theme from 'src/theme';
|
||||
import { uicolors } from 'src/utils/colors';
|
||||
import { getDatesAndPeriodList } from 'src/utils/misc';
|
||||
import DonutChart from '../../components/Charts/DonutChart.vue';
|
||||
import PeriodSelector from './PeriodSelector';
|
||||
@ -72,7 +74,7 @@ export default {
|
||||
expenses: [],
|
||||
}),
|
||||
watch: {
|
||||
period(new_, old) {
|
||||
period() {
|
||||
this.setData();
|
||||
},
|
||||
},
|
||||
@ -89,7 +91,7 @@ export default {
|
||||
sectors() {
|
||||
return this.expenses.map(({ account, color, total }) => ({
|
||||
color,
|
||||
label: account,
|
||||
label: truncate(account, { length: 21 }),
|
||||
value: total,
|
||||
}));
|
||||
},
|
||||
@ -103,11 +105,11 @@ export default {
|
||||
);
|
||||
|
||||
const shades = [
|
||||
{ class: 'bg-gray-800', hex: theme.backgroundColor.gray['800'] },
|
||||
{ class: 'bg-gray-600', hex: theme.backgroundColor.gray['600'] },
|
||||
{ class: 'bg-gray-400', hex: theme.backgroundColor.gray['400'] },
|
||||
{ class: 'bg-gray-300', hex: theme.backgroundColor.gray['300'] },
|
||||
{ class: 'bg-gray-200', hex: theme.backgroundColor.gray['200'] },
|
||||
{ class: 'bg-pink-500', hex: uicolors.pink['500'] },
|
||||
{ class: 'bg-pink-400', hex: uicolors.pink['400'] },
|
||||
{ class: 'bg-pink-300', hex: uicolors.pink['300'] },
|
||||
{ class: 'bg-pink-200', hex: uicolors.pink['200'] },
|
||||
{ class: 'bg-pink-100', hex: uicolors.pink['100'] },
|
||||
];
|
||||
|
||||
topExpenses = topExpenses
|
||||
|
@ -11,7 +11,9 @@
|
||||
</template>
|
||||
</SectionHeader>
|
||||
<BarChart
|
||||
class="mt-4"
|
||||
v-if="hasData"
|
||||
:aspect-ratio="2.05"
|
||||
:colors="chartData.colors"
|
||||
:points="chartData.points"
|
||||
:x-labels="chartData.xLabels"
|
||||
@ -31,6 +33,7 @@
|
||||
import BarChart from 'src/components/Charts/BarChart.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { formatXLabels, getYMax, getYMin } from 'src/utils/chart';
|
||||
import { uicolors } from 'src/utils/colors';
|
||||
import { getDatesAndPeriodList } from 'src/utils/misc';
|
||||
import { getValueMapFromList } from 'utils';
|
||||
import PeriodSelector from './PeriodSelector';
|
||||
@ -57,7 +60,9 @@ export default {
|
||||
computed: {
|
||||
chartData() {
|
||||
const points = [this.data.map((d) => d.balance)];
|
||||
const colors = [{ positive: '#2490EF', negative: '#B7BFC6' }];
|
||||
const colors = [
|
||||
{ positive: uicolors.blue['500'], negative: uicolors.pink['500'] },
|
||||
];
|
||||
const format = (value) => fyo.format(value ?? 0, 'Currency');
|
||||
const yMax = getYMax(points);
|
||||
const yMin = getYMin(points);
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="flex items-baseline justify-between">
|
||||
<span class="font-medium"><slot name="title"></slot></span>
|
||||
<span class="font-medium text-base"><slot name="title"></slot></span>
|
||||
<slot name="action"></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="flex justify-between gap-8">
|
||||
<div class="flex">
|
||||
<div
|
||||
class="flex-col justify-between flex-1"
|
||||
v-for="(invoice, i) in invoices"
|
||||
class="flex-col justify-between w-full p-4"
|
||||
:class="i === 0 ? 'border-r' : ''"
|
||||
:key="invoice.title"
|
||||
>
|
||||
<!-- Title and Period Selector -->
|
||||
@ -26,9 +27,9 @@
|
||||
</SectionHeader>
|
||||
|
||||
<!-- Widget Body -->
|
||||
<div>
|
||||
<div class="mt-4">
|
||||
<!-- Paid & Unpaid Amounts -->
|
||||
<div class="mt-6 flex justify-between">
|
||||
<div class="flex justify-between">
|
||||
<!-- Paid -->
|
||||
<div
|
||||
class="text-sm bold"
|
||||
@ -63,6 +64,8 @@
|
||||
:class="
|
||||
invoice.count && invoice.color == 'blue'
|
||||
? 'bg-blue-200'
|
||||
: invoice.hasData
|
||||
? 'bg-pink-200'
|
||||
: 'bg-gray-200'
|
||||
"
|
||||
></div>
|
||||
@ -71,7 +74,9 @@
|
||||
:class="
|
||||
invoice.count && invoice.color == 'blue'
|
||||
? 'bg-blue-500'
|
||||
: 'bg-gray-500'
|
||||
: invoice.hasData
|
||||
? 'bg-pink-500'
|
||||
: 'bg-gray-400'
|
||||
"
|
||||
:style="`width: ${invoice.barWidth}%`"
|
||||
></div>
|
||||
@ -106,6 +111,7 @@ import { ModelNameEnum } from 'models/types';
|
||||
import Button from 'src/components/Button.vue';
|
||||
import MouseFollower from 'src/components/MouseFollower.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { uicolors } from 'src/utils/colors';
|
||||
import { getDatesAndPeriodList } from 'src/utils/misc';
|
||||
import { routeTo } from 'src/utils/ui';
|
||||
import PeriodSelector from './PeriodSelector.vue';
|
||||
@ -121,7 +127,7 @@ export default {
|
||||
},
|
||||
data: () => ({
|
||||
idx: -1,
|
||||
colors: ['#33A1FF', '#B7BFC6'],
|
||||
colors: [uicolors.blue['400'], uicolors.pink['400']],
|
||||
invoices: [
|
||||
{
|
||||
title: t`Sales Invoices`,
|
||||
|
@ -15,12 +15,19 @@
|
||||
>
|
||||
</PageHeader>
|
||||
|
||||
<div
|
||||
class="flex px-4 mt-2 text-base w-full flex-col gap-8"
|
||||
v-if="!complete"
|
||||
>
|
||||
<div class="flex text-base w-full flex-col" v-if="!complete">
|
||||
<!-- Type selector -->
|
||||
<div class="flex flex-row justify-start items-center w-full gap-2">
|
||||
<div
|
||||
class="
|
||||
flex flex-row
|
||||
justify-start
|
||||
items-center
|
||||
w-full
|
||||
gap-2
|
||||
border-b
|
||||
p-4
|
||||
"
|
||||
>
|
||||
<FormControl
|
||||
:df="importableDf"
|
||||
input-class="bg-transparent text-gray-900 text-base"
|
||||
@ -45,9 +52,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Settings -->
|
||||
<div v-if="fileName" class="">
|
||||
<div v-if="fileName" class="border-b p-4">
|
||||
<h2 class="text-lg font-semibold">{{ t`Importer Settings` }}</h2>
|
||||
<div class="mt-4 flex gap-2">
|
||||
<div class="mt-2 flex gap-2">
|
||||
<div
|
||||
v-if="file && isSubmittable"
|
||||
class="
|
||||
@ -124,11 +131,14 @@
|
||||
</div>
|
||||
|
||||
<!-- Label Assigner -->
|
||||
<div v-if="fileName" class="pb-4">
|
||||
<h2 class="text-lg font-semibold">{{ t`Assign Imported Labels` }}</h2>
|
||||
<div
|
||||
class="gap-2 mt-4 grid grid-flow-col overflow-x-auto no-scrollbar"
|
||||
>
|
||||
<div v-if="fileName" class="p-4 border-b">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="text-lg font-semibold">{{ t`Assign Imported Labels` }}</h2>
|
||||
<p class="text-red-400 text-sm" v-if="isRequiredUnassigned">
|
||||
{{ t`* required fields` }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="gap-2 mt-4 grid grid-flow-col overflow-x-auto no-scrollbar">
|
||||
<div
|
||||
v-for="(f, k) in importer.assignableLabels"
|
||||
:key="'assigner-' + f + '-' + k"
|
||||
@ -151,24 +161,24 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
class="text-red-400 text-sm mt-1 -mb-1 p-0 h-0"
|
||||
v-if="isRequiredUnassigned"
|
||||
>
|
||||
{{ t`* required fields` }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Data Verifier -->
|
||||
<div v-if="fileName">
|
||||
<h2 class="-mt-4 text-lg font-semibold pb-1">
|
||||
{{ t`Verify Imported Data` }}
|
||||
</h2>
|
||||
|
||||
<div class="overflow-auto mt-4 pb-4">
|
||||
<div class="overflow-auto border-b">
|
||||
<!-- Column Name Rows -->
|
||||
<div
|
||||
class="grid grid-flow-col pb-4 border-b gap-2 sticky top-0 bg-white"
|
||||
class="
|
||||
grid grid-flow-col
|
||||
border-b
|
||||
gap-2
|
||||
sticky
|
||||
top-0
|
||||
bg-white
|
||||
px-4
|
||||
h-row-mid
|
||||
items-center
|
||||
"
|
||||
style="width: fit-content"
|
||||
v-if="importer.columnLabels.length > 0"
|
||||
>
|
||||
@ -190,10 +200,17 @@
|
||||
<!-- Data Rows -->
|
||||
<div
|
||||
v-if="importer.columnLabels.length > 0"
|
||||
style="max-height: 400px"
|
||||
style="max-height: 500px"
|
||||
>
|
||||
<div
|
||||
class="grid grid-flow-col mt-4 pb-4 border-b gap-2 items-center"
|
||||
class="
|
||||
grid grid-flow-col
|
||||
border-b
|
||||
gap-2
|
||||
items-center
|
||||
px-4
|
||||
h-row-mid
|
||||
"
|
||||
style="width: fit-content"
|
||||
v-for="(r, i) in assignedMatrix"
|
||||
:key="'matrix-row-' + i"
|
||||
@ -238,13 +255,18 @@
|
||||
:value="c"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Add Row button -->
|
||||
<button
|
||||
class="
|
||||
text-gray-600
|
||||
hover:text-gray-900
|
||||
hover:bg-gray-50
|
||||
flex flex-row
|
||||
w-full
|
||||
mt-4
|
||||
px-4
|
||||
h-row-mid
|
||||
border-b
|
||||
items-center
|
||||
outline-none
|
||||
"
|
||||
@click="
|
||||
|
@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div
|
||||
class="py-10 flex-1 bg-white flex justify-center items-center"
|
||||
class="flex-1 flex justify-center items-center bg-gray-25"
|
||||
:class="{
|
||||
'pointer-events-none': loadingDatabase,
|
||||
'window-drag': platform !== 'Windows',
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="w-full w-form shadow rounded-lg border relative"
|
||||
class="w-full w-form shadow-lg rounded-lg border relative bg-white"
|
||||
style="height: 700px"
|
||||
>
|
||||
<!-- Welcome to Frappe Books -->
|
||||
<div class="px-6 py-10">
|
||||
<div class="px-4 py-4">
|
||||
<h1 class="text-2xl font-semibold select-none">
|
||||
{{ t`Welcome to Frappe Books` }}
|
||||
</h1>
|
||||
@ -27,8 +27,8 @@
|
||||
<!-- New File (Blue Icon) -->
|
||||
<div
|
||||
@click="newDatabase"
|
||||
class="px-6 h-18 flex flex-row items-center gap-4 p-2"
|
||||
:class="creatingDemo ? '' : 'hover:bg-gray-100 cursor-pointer'"
|
||||
class="px-4 h-row-largest flex flex-row items-center gap-4 p-2"
|
||||
:class="creatingDemo ? '' : 'hover:bg-gray-50 cursor-pointer'"
|
||||
>
|
||||
<div class="w-8 h-8 rounded-full bg-blue-500 relative flex-center">
|
||||
<feather-icon name="plus" class="text-white w-5 h-5" />
|
||||
@ -47,8 +47,8 @@
|
||||
<!-- Existing File (Green Icon) -->
|
||||
<div
|
||||
@click="existingDatabase"
|
||||
class="px-6 h-18 flex flex-row items-center gap-4 p-2"
|
||||
:class="creatingDemo ? '' : 'hover:bg-gray-100 cursor-pointer'"
|
||||
class="px-4 h-row-largest flex flex-row items-center gap-4 p-2"
|
||||
:class="creatingDemo ? '' : 'hover:bg-gray-50 cursor-pointer'"
|
||||
>
|
||||
<div class="w-8 h-8 rounded-full bg-green-500 relative flex-center">
|
||||
<feather-icon name="upload" class="w-4 h-4 text-white" />
|
||||
@ -67,8 +67,8 @@
|
||||
<!-- File List -->
|
||||
<div class="overflow-y-auto" style="max-height: 340px">
|
||||
<div
|
||||
class="h-18 px-6 flex gap-4 items-center"
|
||||
:class="creatingDemo ? '' : 'hover:bg-gray-100 cursor-pointer'"
|
||||
class="h-row-largest px-4 flex gap-4 items-center"
|
||||
:class="creatingDemo ? '' : 'hover:bg-gray-50 cursor-pointer'"
|
||||
v-for="(file, i) in files"
|
||||
:key="file.dbPath"
|
||||
@click="selectFile(file)"
|
||||
@ -137,8 +137,7 @@
|
||||
justify-between
|
||||
items-center
|
||||
absolute
|
||||
px-6
|
||||
py-6
|
||||
p-4
|
||||
text-gray-900
|
||||
"
|
||||
style="top: 100%; transform: translateY(-100%)"
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex overflow-hidden">
|
||||
<Sidebar
|
||||
class="w-sidebar flex-shrink-0"
|
||||
class="w-sidebar flex-shrink-0 border-r"
|
||||
@change-db-file="$emit('change-db-file')"
|
||||
/>
|
||||
<div class="flex flex-1 overflow-y-hidden bg-white">
|
||||
|
@ -1,26 +1,21 @@
|
||||
<template>
|
||||
<div class="flex flex-col overflow-y-hidden">
|
||||
<PageHeader :title="t`Setup Your Workspace`" />
|
||||
<div class="flex-1 mx-4 overflow-y-auto overflow-x-hidden">
|
||||
<div class="my-4" v-for="section in sections" :key="section.label">
|
||||
<div class="flex-1 overflow-y-auto overflow-x-hidden">
|
||||
<div
|
||||
class="p-4 border-b"
|
||||
v-for="section in sections"
|
||||
:key="section.label"
|
||||
>
|
||||
<h2 class="font-medium">{{ section.label }}</h2>
|
||||
<div class="flex mt-4 -mx-2">
|
||||
<div class="flex mt-4 gap-4">
|
||||
<div
|
||||
class="flex-shrink-0 w-full px-2 md:w-1/3 sm:w-1/2"
|
||||
class="w-full md:w-1/3 sm:w-1/2"
|
||||
v-for="item in section.items"
|
||||
:key="item.label"
|
||||
>
|
||||
<div
|
||||
class="
|
||||
flex flex-col
|
||||
justify-between
|
||||
h-40
|
||||
p-4
|
||||
border
|
||||
rounded-lg
|
||||
cursor-pointer
|
||||
hover:shadow-md
|
||||
"
|
||||
class="flex flex-col justify-between h-40 p-4 border rounded-lg"
|
||||
@mouseenter="() => (activeCard = item.key)"
|
||||
@mouseleave="() => (activeCard = null)"
|
||||
>
|
||||
|
@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<div class="flex flex-col" v-if="doc">
|
||||
<FormContainer :backLink="true">
|
||||
<!-- Page Header (Title, Buttons, etc) -->
|
||||
<PageHeader :backLink="true">
|
||||
<template #header v-if="doc">
|
||||
<StatusBadge :status="status" />
|
||||
<Button
|
||||
v-if="doc?.submitted"
|
||||
class="text-gray-900 text-xs"
|
||||
:icon="true"
|
||||
@click="routeTo(`/print/${doc.schemaName}/${doc.name}`)"
|
||||
>
|
||||
@ -15,7 +14,6 @@
|
||||
<Button
|
||||
v-if="doc?.notInserted || doc?.dirty"
|
||||
type="primary"
|
||||
class="text-white text-xs"
|
||||
@click="sync"
|
||||
>
|
||||
{{ t`Save` }}
|
||||
@ -23,28 +21,24 @@
|
||||
<Button
|
||||
v-if="!doc?.dirty && !doc?.notInserted && !doc?.submitted"
|
||||
type="primary"
|
||||
class="text-white text-xs"
|
||||
@click="submit"
|
||||
>{{ t`Submit` }}</Button
|
||||
>
|
||||
</PageHeader>
|
||||
</template>
|
||||
|
||||
<!-- Invoice Form -->
|
||||
<div
|
||||
class="
|
||||
border
|
||||
rounded-lg
|
||||
shadow
|
||||
h-full
|
||||
flex flex-col
|
||||
mt-2
|
||||
self-center
|
||||
w-form
|
||||
h-form
|
||||
"
|
||||
v-if="doc"
|
||||
>
|
||||
<div class="p-4 text-2xl font-semibold flex justify-between">
|
||||
<template #body v-if="doc">
|
||||
<div
|
||||
class="
|
||||
px-4
|
||||
text-xl
|
||||
font-semibold
|
||||
flex
|
||||
justify-between
|
||||
h-row-large
|
||||
items-center
|
||||
"
|
||||
>
|
||||
<h1>
|
||||
{{ doc.notInserted ? t`New Entry` : doc.name }}
|
||||
</h1>
|
||||
@ -115,7 +109,7 @@
|
||||
|
||||
<div v-if="doc.items?.length ?? 0" class="mt-auto">
|
||||
<hr />
|
||||
<div class="flex justify-between text-base m-6 gap-12">
|
||||
<div class="flex justify-between text-base m-4 gap-12">
|
||||
<!-- Form Terms-->
|
||||
<FormControl
|
||||
class="w-1/2 self-end"
|
||||
@ -180,8 +174,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</FormContainer>
|
||||
</template>
|
||||
<script>
|
||||
import { computed } from '@vue/reactivity';
|
||||
@ -191,7 +185,7 @@ import Button from 'src/components/Button.vue';
|
||||
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||
import Table from 'src/components/Controls/Table.vue';
|
||||
import DropdownWithActions from 'src/components/DropdownWithActions.vue';
|
||||
import PageHeader from 'src/components/PageHeader.vue';
|
||||
import FormContainer from 'src/components/FormContainer.vue';
|
||||
import StatusBadge from 'src/components/StatusBadge.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import {
|
||||
@ -206,12 +200,12 @@ export default {
|
||||
name: 'InvoiceForm',
|
||||
props: { schemaName: String, name: String },
|
||||
components: {
|
||||
PageHeader,
|
||||
StatusBadge,
|
||||
Button,
|
||||
FormControl,
|
||||
DropdownWithActions,
|
||||
Table,
|
||||
FormContainer,
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
@ -245,9 +239,7 @@ export default {
|
||||
await this.handleError(error);
|
||||
}
|
||||
this.printSettings = await fyo.doc.getDoc('PrintSettings');
|
||||
this.companyName = (
|
||||
await fyo.doc.getDoc('AccountingSettings')
|
||||
).companyName;
|
||||
this.companyName = (await fyo.doc.getDoc('AccountingSettings')).companyName;
|
||||
|
||||
let query = this.$route.query;
|
||||
if (query.values && query.schemaName === this.schemaName) {
|
||||
|
@ -1,44 +1,30 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<FormContainer :backLink="true">
|
||||
<!-- Page Header (Title, Buttons, etc) -->
|
||||
<PageHeader :backLink="true">
|
||||
<template v-if="doc">
|
||||
<StatusBadge :status="status" />
|
||||
<DropdownWithActions :actions="actions" />
|
||||
<Button
|
||||
v-if="doc?.notInserted || doc?.dirty"
|
||||
type="primary"
|
||||
class="text-white text-xs"
|
||||
@click="sync"
|
||||
>
|
||||
{{ t`Save` }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="!doc.dirty && !doc.notInserted && !doc.submitted"
|
||||
type="primary"
|
||||
class="text-white text-xs"
|
||||
@click="submit"
|
||||
>
|
||||
{{ t`Submit` }}
|
||||
</Button>
|
||||
</template>
|
||||
</PageHeader>
|
||||
<template #header v-if="doc">
|
||||
<StatusBadge :status="status" />
|
||||
<DropdownWithActions :actions="actions" />
|
||||
<Button
|
||||
v-if="doc?.notInserted || doc?.dirty"
|
||||
type="primary"
|
||||
class="text-white text-xs"
|
||||
@click="sync"
|
||||
>
|
||||
{{ t`Save` }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="!doc.dirty && !doc.notInserted && !doc.submitted"
|
||||
type="primary"
|
||||
class="text-white text-xs"
|
||||
@click="submit"
|
||||
>
|
||||
{{ t`Submit` }}
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<!-- Journal Entry Form -->
|
||||
<div
|
||||
class="
|
||||
self-center
|
||||
border
|
||||
rounded-lg
|
||||
shadow
|
||||
flex flex-col
|
||||
mt-2
|
||||
w-form
|
||||
h-form
|
||||
"
|
||||
v-if="doc"
|
||||
>
|
||||
<div class="p-4 text-2xl font-semibold flex justify-between">
|
||||
<template #body v-if="doc">
|
||||
<div class="px-4 text-xl font-semibold flex justify-between h-row-large items-center">
|
||||
<h1>
|
||||
{{ doc.notInserted ? t`New Entry` : doc.name }}
|
||||
</h1>
|
||||
@ -112,7 +98,7 @@
|
||||
<!-- Footer -->
|
||||
<div v-if="doc.accounts?.length ?? 0" class="mt-auto">
|
||||
<hr />
|
||||
<div class="flex justify-between text-base m-6 gap-12">
|
||||
<div class="flex justify-between text-base m-4 gap-12">
|
||||
<!-- User Remark -->
|
||||
<FormControl
|
||||
v-if="!doc.submitted || doc.userRemark"
|
||||
@ -139,18 +125,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</FormContainer>
|
||||
</template>
|
||||
<script>
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { ModelNameEnum } from 'models/types';
|
||||
import Button from 'src/components/Button';
|
||||
import Button from 'src/components/Button.vue';
|
||||
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||
import Table from 'src/components/Controls/Table.vue';
|
||||
import DropdownWithActions from 'src/components/DropdownWithActions';
|
||||
import PageHeader from 'src/components/PageHeader';
|
||||
import StatusBadge from 'src/components/StatusBadge';
|
||||
import DropdownWithActions from 'src/components/DropdownWithActions.vue';
|
||||
import FormContainer from 'src/components/FormContainer.vue';
|
||||
import StatusBadge from 'src/components/StatusBadge.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import {
|
||||
getActionsForDocument,
|
||||
@ -163,12 +149,12 @@ export default {
|
||||
name: 'JournalEntryForm',
|
||||
props: ['name'],
|
||||
components: {
|
||||
PageHeader,
|
||||
Button,
|
||||
DropdownWithActions,
|
||||
StatusBadge,
|
||||
FormControl,
|
||||
Table,
|
||||
FormContainer,
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
|
@ -1,19 +1,26 @@
|
||||
<template>
|
||||
<div class="mx-4 text-base flex flex-col overflow-y-hidden">
|
||||
<div class="text-base flex flex-col overflow-y-hidden">
|
||||
<!-- Title Row -->
|
||||
<div class="flex items-center">
|
||||
<p class="w-8 text-right mr-4 text-gray-700">#</p>
|
||||
<Row
|
||||
class="flex-1 text-gray-700 border-none"
|
||||
class="flex-1 text-gray-700 border-none h-row-mid"
|
||||
:columnCount="columns.length"
|
||||
gap="1rem"
|
||||
>
|
||||
<div
|
||||
v-for="(column, i) in columns"
|
||||
:key="column.label"
|
||||
class="py-4 overflow-x-auto no-scrollbar whitespace-nowrap"
|
||||
class="
|
||||
overflow-x-auto
|
||||
no-scrollbar
|
||||
whitespace-nowrap
|
||||
h-row
|
||||
items-center
|
||||
flex
|
||||
"
|
||||
:class="{
|
||||
'text-right': isNumeric(column.fieldtype),
|
||||
'ml-auto': isNumeric(column.fieldtype),
|
||||
'pr-4': i === columns.length - 1,
|
||||
}"
|
||||
>
|
||||
@ -27,13 +34,13 @@
|
||||
<div class="overflow-y-auto" v-if="dataSlice.length !== 0">
|
||||
<div v-for="(doc, i) in dataSlice" :key="doc.name">
|
||||
<!-- Row Content -->
|
||||
<div class="flex hover:bg-gray-100 items-center">
|
||||
<div class="flex hover:bg-gray-50 items-center">
|
||||
<p class="w-8 text-right mr-4 text-gray-900">
|
||||
{{ i + pageStart + 1 }}
|
||||
</p>
|
||||
<Row
|
||||
gap="1rem"
|
||||
class="cursor-pointer text-gray-900 flex-1 border-none"
|
||||
class="cursor-pointer text-gray-900 flex-1 border-none h-row-mid"
|
||||
@click="openForm(doc)"
|
||||
:columnCount="columns.length"
|
||||
>
|
||||
@ -49,14 +56,18 @@
|
||||
/>
|
||||
</Row>
|
||||
</div>
|
||||
<hr v-if="i !== dataSlice.length - 1" />
|
||||
<hr v-if="!(i === dataSlice.length - 1 && i > 13)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination Footer -->
|
||||
<div class="mt-auto" v-if="data?.length">
|
||||
<hr />
|
||||
<Paginator :item-count="data.length" @index-change="setPageIndices" />
|
||||
<Paginator
|
||||
:item-count="data.length"
|
||||
@index-change="setPageIndices"
|
||||
class="px-4"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Empty State -->
|
||||
|
@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="py-4 flex items-center truncate" :class="cellClass">
|
||||
<div class="flex items-center truncate" :class="cellClass">
|
||||
<span class="truncate" v-if="!customRenderer">{{ columnValue }}</span>
|
||||
<component v-else :is="customRenderer" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { isNumeric } from 'src/utils';
|
||||
|
||||
export default {
|
||||
name: 'ListCell',
|
||||
@ -21,9 +22,7 @@ export default {
|
||||
return this.column.render(this.doc);
|
||||
},
|
||||
cellClass() {
|
||||
return ['Int', 'Float', 'Currency'].includes(this.column.fieldtype)
|
||||
? 'justify-end'
|
||||
: '';
|
||||
return isNumeric(this.column.fieldtype) ? 'justify-end' : '';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex">
|
||||
<div class="flex flex-col flex-1">
|
||||
<PageHeader :backLink="true" class="bg-white z-10">
|
||||
<div class="flex flex-col flex-1 bg-gray-25">
|
||||
<PageHeader :backLink="true" class="z-10" :border="false">
|
||||
<Button
|
||||
class="text-gray-900 text-xs"
|
||||
@click="showCustomiser = !showCustomiser"
|
||||
@ -16,15 +16,14 @@
|
||||
<!-- Printview Preview -->
|
||||
<div
|
||||
v-if="doc && printSettings"
|
||||
class="flex justify-center flex-1 -mt-36 overflow-auto relative"
|
||||
class="flex justify-center flex-1 overflow-auto relative"
|
||||
>
|
||||
<div
|
||||
class="h-full shadow-lg mb-12 absolute"
|
||||
class="h-full shadow mb-4 absolute bg-white"
|
||||
style="
|
||||
width: 21cm;
|
||||
min-height: 29.7cm;
|
||||
height: max-content;
|
||||
transform: scale(0.7);
|
||||
height: 29.7cm;
|
||||
transform: scale(0.65) translateY(-300px);
|
||||
"
|
||||
ref="printContainer"
|
||||
>
|
||||
@ -39,13 +38,19 @@
|
||||
|
||||
<!-- Printview Customizer -->
|
||||
<div class="border-l w-80" v-if="showCustomiser">
|
||||
<div class="mt-4 px-4 flex items-center justify-between">
|
||||
<div
|
||||
class="px-4 flex items-center justify-between h-row-largest border-b"
|
||||
>
|
||||
<h2 class="font-semibold">{{ t`Customise` }}</h2>
|
||||
<Button :icon="true" @click="showCustomiser = false">
|
||||
<feather-icon name="x" class="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<TwoColumnForm class="mt-4" :doc="printSettings" :autosave="true" />
|
||||
<TwoColumnForm
|
||||
:doc="printSettings"
|
||||
:autosave="true"
|
||||
class="border-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<div class="border-l h-full overflow-auto">
|
||||
<div
|
||||
class="border-l h-full overflow-auto"
|
||||
:class="white ? 'bg-white' : 'bg-gray-25'"
|
||||
>
|
||||
<!-- Quick edit Tool bar -->
|
||||
<div class="flex items-center justify-between px-4 pt-4">
|
||||
<div class="flex items-center justify-between px-4 border-b h-row-largest">
|
||||
<!-- Close Button and Status Text -->
|
||||
<div class="flex items-center">
|
||||
<Button :icon="true" @click="routeToPrevious">
|
||||
@ -43,7 +46,11 @@
|
||||
</div>
|
||||
|
||||
<!-- Name and image -->
|
||||
<div class="p-4 gap-2 flex-center flex flex-col items-center" v-if="doc">
|
||||
<div
|
||||
class="px-4 flex-center flex flex-col items-center gap-1.5"
|
||||
style="height: calc(var(--h-row-mid) * 2 + 1px)"
|
||||
v-if="doc"
|
||||
>
|
||||
<FormControl
|
||||
v-if="imageField"
|
||||
:df="imageField"
|
||||
@ -53,7 +60,7 @@
|
||||
:letter-placeholder="doc[titleField.fieldname]?.[0] ?? null"
|
||||
/>
|
||||
<FormControl
|
||||
input-class="text-center"
|
||||
input-class="text-center h-8 bg-transparent"
|
||||
ref="titleControl"
|
||||
v-if="titleField"
|
||||
:df="titleField"
|
||||
@ -97,6 +104,7 @@ export default {
|
||||
name: String,
|
||||
schemaName: String,
|
||||
defaults: String,
|
||||
white: { type: Boolean, default: false },
|
||||
hideFields: { type: Array, default: () => [] },
|
||||
showFields: { type: Array, default: () => [] },
|
||||
},
|
||||
|
@ -3,6 +3,7 @@
|
||||
<PageHeader :title="title">
|
||||
<DropdownWithActions
|
||||
v-for="group of groupedActions"
|
||||
:icon="false"
|
||||
:key="group.label"
|
||||
:type="group.type"
|
||||
:actions="group.actions"
|
||||
@ -13,7 +14,7 @@
|
||||
</PageHeader>
|
||||
|
||||
<!-- Filters -->
|
||||
<div v-if="report" class="mx-4 grid grid-cols-5 gap-2">
|
||||
<div v-if="report" class="grid grid-cols-5 gap-2 p-4 border-b">
|
||||
<FormControl
|
||||
v-for="field in report.filters"
|
||||
size="small"
|
||||
@ -30,7 +31,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Report Body -->
|
||||
<ListReport v-if="report" :report="report" class="mx-4 mt-4" />
|
||||
<ListReport v-if="report" :report="report" class="" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
@ -1,22 +1,8 @@
|
||||
<template>
|
||||
<div class="flex flex-col overflow-hidden">
|
||||
<PageHeader :title="t`Settings`" />
|
||||
<div
|
||||
class="
|
||||
border
|
||||
rounded-lg
|
||||
shadow
|
||||
h-full
|
||||
flex flex-col
|
||||
justify-between
|
||||
self-center
|
||||
mt-2
|
||||
w-form
|
||||
h-form
|
||||
"
|
||||
>
|
||||
<FormContainer :title="t`Settings`">
|
||||
<template #body>
|
||||
<!-- Icon Tab Bar -->
|
||||
<div class="flex justify-around mb-4 mt-6">
|
||||
<div class="flex justify-around mb-2 mt-4">
|
||||
<div
|
||||
v-for="(tab, i) in tabs"
|
||||
:key="tab.label"
|
||||
@ -39,13 +25,14 @@
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<component :is="activeTabComponent" @change="handleChange" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</FormContainer>
|
||||
</template>
|
||||
<script>
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { t } from 'fyo';
|
||||
import Button from 'src/components/Button.vue';
|
||||
import FormContainer from 'src/components/FormContainer.vue';
|
||||
import Icon from 'src/components/Icon.vue';
|
||||
import PageHeader from 'src/components/PageHeader.vue';
|
||||
import Row from 'src/components/Row.vue';
|
||||
@ -64,6 +51,7 @@ export default {
|
||||
StatusBadge,
|
||||
Button,
|
||||
Row,
|
||||
FormContainer,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -61,9 +61,7 @@ export default {
|
||||
},
|
||||
async mounted() {
|
||||
this.doc = await fyo.doc.getDoc('PrintSettings');
|
||||
this.companyName = (
|
||||
await fyo.doc.getDoc('AccountingSettings')
|
||||
).companyName;
|
||||
this.companyName = (await fyo.doc.getDoc('AccountingSettings')).companyName;
|
||||
},
|
||||
computed: {
|
||||
fields() {
|
||||
|
@ -8,10 +8,15 @@
|
||||
:emit-change="true"
|
||||
@change="forwardChangeEvent"
|
||||
/>
|
||||
<LanguageSelector
|
||||
class="text-sm w-28 bg-gray-100 rounded-md mb-6 ml-6"
|
||||
input-class="py-1.5 bg-transparent"
|
||||
/>
|
||||
<div class="flex p-4 justify-between">
|
||||
<LanguageSelector
|
||||
class="text-sm w-28 bg-gray-100 rounded-md"
|
||||
input-class="py-1.5 bg-transparent"
|
||||
/>
|
||||
<p class="mt-auto text-gray-600 text-base select-none">
|
||||
{{ `v${fyo.store.appVersion}` }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="py-10 flex-1 bg-white flex justify-center items-center window-drag"
|
||||
>
|
||||
<div class="flex-1 bg-gray-25 flex justify-center items-center window-drag">
|
||||
<!-- 0: Language Selection Slide -->
|
||||
<Slide
|
||||
@primary-clicked="handlePrimary"
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="w-form shadow rounded-lg border relative" style="height: 700px">
|
||||
<div class="w-form shadow-lg rounded-lg border relative bg-white" style="height: 700px">
|
||||
<!-- Slide Title -->
|
||||
<div class="px-6 py-10">
|
||||
<div class="p-4">
|
||||
<h1 class="text-2xl font-semibold select-none">
|
||||
<slot name="title"></slot>
|
||||
</h1>
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
<!-- Slide Buttons -->
|
||||
<div
|
||||
class="flex justify-between px-6 pb-6 window-no-drag absolute w-form"
|
||||
class="flex justify-between px-4 pb-4 window-no-drag absolute w-form"
|
||||
style="top: 100%; transform: translateY(-100%)"
|
||||
>
|
||||
<Button
|
||||
|
@ -53,6 +53,22 @@ html {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:root {
|
||||
--w-app: 1200px;
|
||||
--w-sidebar: 12rem;
|
||||
--w-desk: calc(100vw - var(--w-sidebar));
|
||||
--w-desk-fixed: calc(var(--w-app) - var(--w-sidebar));
|
||||
--w-scrollbar: 0.5rem;
|
||||
|
||||
/* Row Heights */
|
||||
--h-row-smallest: 2rem;
|
||||
--h-row-small: 2.5rem;
|
||||
--h-row-mid: 3rem;
|
||||
--h-row-large: 3.5rem;
|
||||
--h-row-largest: 4rem;
|
||||
--h-app: 800px;
|
||||
}
|
||||
|
||||
.w-form {
|
||||
width: 600px;
|
||||
}
|
||||
@ -61,10 +77,30 @@ html {
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
.h-row-smallest {
|
||||
height: var(--h-row-smallest);
|
||||
}
|
||||
|
||||
.h-row-small {
|
||||
height: var(--h-row-small);
|
||||
}
|
||||
|
||||
.h-row-mid {
|
||||
height: var(--h-row-mid);
|
||||
}
|
||||
|
||||
.h-row-large {
|
||||
height: var(--h-row-large);
|
||||
}
|
||||
|
||||
.h-row-largest {
|
||||
height: var(--h-row-largest);
|
||||
}
|
||||
|
||||
.w-sidebar {
|
||||
width: 12rem;
|
||||
width: var(--w-sidebar);
|
||||
}
|
||||
|
||||
.w-desk {
|
||||
width: calc(100vw - 12rem);
|
||||
width: var(--w-desk);
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
import resolveConfig from 'tailwindcss/resolveConfig';
|
||||
import tailwindConfig from '../tailwind.config';
|
||||
|
||||
export default resolveConfig(tailwindConfig).theme;
|
@ -1,3 +1,7 @@
|
||||
import { theme } from '../../tailwind.config';
|
||||
|
||||
export const uicolors = theme.extend.colors;
|
||||
|
||||
export const indicators = {
|
||||
GRAY: 'grey',
|
||||
GREY: 'grey',
|
||||
@ -34,7 +38,8 @@ const getValidColor = (color: string) => {
|
||||
};
|
||||
|
||||
export function getBgColorClass(color: string) {
|
||||
return `bg-${getValidColor(color)}-100`;
|
||||
const vcolor = getValidColor(color);
|
||||
return `bg-${vcolor}-100`;
|
||||
}
|
||||
|
||||
export function getColorClass(color: string, type: 'bg' | 'text', value = 300) {
|
||||
|
@ -57,19 +57,19 @@ module.exports = {
|
||||
'span-full': '1 / -1',
|
||||
},
|
||||
colors: {
|
||||
brand: '#2490EF',
|
||||
'brand-100': '#f4f9ff',
|
||||
black: '#112B42',
|
||||
black: '#1E293B',
|
||||
gray: {
|
||||
100: '#f4f4f6',
|
||||
200: '#e9ebed',
|
||||
300: '#dfe1e2',
|
||||
400: '#cccfd1',
|
||||
500: '#b7bfc6',
|
||||
600: '#a1abb4',
|
||||
700: '#9fa5a8',
|
||||
800: '#7f878a',
|
||||
900: '#415668',
|
||||
25: '#fcfcfd',
|
||||
50: '#f8f9fc',
|
||||
100: '#f2f4f8',
|
||||
200: '#ebeff5',
|
||||
300: '#e2e8f0',
|
||||
400: '#cad5e2',
|
||||
500: '#9aa8bc',
|
||||
600: '#8493a9',
|
||||
700: '#64748b',
|
||||
800: '#475569',
|
||||
900: '#334155',
|
||||
},
|
||||
red: {
|
||||
100: '#fff5f5',
|
||||
@ -132,7 +132,7 @@ module.exports = {
|
||||
300: '#99d0ff',
|
||||
400: '#66b8ff',
|
||||
500: '#33a1ff',
|
||||
600: '#0089ff',
|
||||
600: '#2490ef',
|
||||
700: '#006ecc',
|
||||
800: '#005299',
|
||||
900: '#003766',
|
||||
@ -160,15 +160,15 @@ module.exports = {
|
||||
900: '#44337a',
|
||||
},
|
||||
pink: {
|
||||
100: '#fff5f7',
|
||||
200: '#fed7e2',
|
||||
300: '#fbb6ce',
|
||||
400: '#f687b3',
|
||||
500: '#ed64a6',
|
||||
600: '#d53f8c',
|
||||
700: '#b83280',
|
||||
800: '#97266d',
|
||||
900: '#702459',
|
||||
100: '#fdf7f8',
|
||||
200: '#fbeef1',
|
||||
300: '#f7dee5',
|
||||
400: '#eec3d2',
|
||||
500: '#df9eb8',
|
||||
600: '#cf82a7',
|
||||
700: '#ac688b',
|
||||
800: '#8f5b79',
|
||||
900: '#70485f',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user