├── .gitattributes ├── LICENSE ├── README.md ├── assets ├── css │ ├── bootstrap.min.css │ └── styles.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── images │ ├── icon.icns │ ├── icon.ico │ └── sending.gif ├── js │ └── scripts.js └── plugins │ ├── bootstrap │ ├── bootstrap.min.css │ └── bootstrap.min.js │ ├── dataTables │ ├── buttons.html5.min.js │ ├── buttons.print.min.js │ ├── dataTables.bootstrap.min.css │ ├── dataTables.buttons.min.js │ ├── extensions │ │ ├── ColVis │ │ │ └── js │ │ │ │ └── dataTables.colVis.js │ │ └── TableTools │ │ │ └── js │ │ │ └── dataTables.tableTools.js │ ├── jquery.dataTables.bootstrap.js │ ├── jquery.dataTables.min.css │ ├── jquery.dataTables.min.js │ ├── pdfmake.min.js │ └── vfs_fonts.js │ ├── daterangepicker │ ├── bootstrap.datetime.js │ ├── bootstrap.datetimepicker.css │ ├── daterangepicker.css │ ├── daterangepicker.min.js │ └── moment.min.js │ ├── images │ ├── Sorting icons.psd │ ├── favicon.ico │ ├── sort_asc.png │ ├── sort_asc_disabled.png │ ├── sort_both.png │ ├── sort_desc.png │ └── sort_desc_disabled.png │ └── jquery-ui │ ├── AUTHORS.txt │ ├── LICENSE.txt │ ├── images │ ├── ui-icons_444444_256x240.png │ ├── ui-icons_555555_256x240.png │ ├── ui-icons_777620_256x240.png │ ├── ui-icons_777777_256x240.png │ ├── ui-icons_cc0000_256x240.png │ └── ui-icons_ffffff_256x240.png │ ├── index.html │ ├── jquery-ui.css │ ├── jquery-ui.js │ ├── jquery-ui.min.css │ ├── jquery-ui.min.js │ ├── jquery-ui.structure.css │ ├── jquery-ui.structure.min.css │ ├── jquery-ui.theme.css │ ├── jquery-ui.theme.min.css │ ├── jquery.form.min.js │ └── package.json ├── docs ├── CNAME ├── css │ └── reset.css ├── images │ ├── checked-pricing-white.png │ ├── checked-pricing.png │ ├── checked.png │ ├── drop-down.png │ ├── icons │ │ └── icons-64 │ │ │ ├── GitHub-Mark-32px.png │ │ │ ├── GitHub_Logo.png │ │ │ ├── desktop-chart-64.png │ │ │ ├── globe-64.png │ │ │ ├── security-64.png │ │ │ ├── support-64.png │ │ │ ├── target-64.png │ │ │ └── wallet-64.png │ ├── intro-animation.gif │ ├── intro-animation.png │ ├── logo.png │ └── social │ │ └── black │ │ ├── facebook.png │ │ ├── linkedin.png │ │ └── twitter.png ├── index.html ├── js │ ├── jquery-3.3.1.min.js │ ├── jquery.custom.js │ ├── jquery.paroller.min.js │ └── menu.js └── style.css ├── index.html ├── package.json ├── public ├── favicon.ico ├── index.html └── robots.txt ├── screenshots ├── create_invoice.png ├── dashboard.png ├── invoices.png └── pdf_invoice.png ├── setupEvents.js └── start.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ngoms 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Offline Invoicing 2 | Desktop invoicing app built with electron 3 | 4 | **To use on Windows:** 5 | [Download](http://download.offlineinvoicing.com/OfflineInvoicing.msi) the MSI Installer 6 | 7 | **To Customize/Create your own installer** 8 | 9 | - Clone this project. 10 | - Open terminal and navigate into the cloned folder. 11 | - Run "npm install" to install dependencies. 12 | - Run "npm run electron". 13 | 14 | ![Create Invoice](https://github.com/tngoman/Offline_Invoicing/blob/master/screenshots/create_invoice.png) 15 | 16 | ![Invoice List](https://github.com/tngoman/Offline_Invoicing/blob/master/screenshots/invoices.png) 17 | 18 | ![PDF Invoice](https://github.com/tngoman/Offline_Invoicing/blob/master/screenshots/pdf_invoice.png) 19 | 20 | ![Dashboard](https://github.com/tngoman/Offline_Invoicing/blob/master/screenshots/dashboard.png) 21 | -------------------------------------------------------------------------------- /assets/css/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | height: 100%; 3 | margin: 0; 4 | overflow: hidden; 5 | position:relative; 6 | } 7 | 8 | .clear { 9 | clear: both; 10 | } 11 | 12 | .panel-body { 13 | padding: 15px 15px 0 15px; 14 | } 15 | 16 | 17 | .btn { 18 | border-radius: 3px; 19 | outline: none !important; 20 | } 21 | .btn-md { 22 | padding: 8px 16px; 23 | } 24 | .btn-primary, 25 | .btn-success, 26 | .btn-default, 27 | .btn-info, 28 | .btn-warning, 29 | .btn-danger, 30 | .btn-inverse, 31 | .btn-purple, 32 | .btn-pink { 33 | color: #ffffff !important; 34 | } 35 | .btn-default, 36 | .btn-default:hover, 37 | .btn-default:focus, 38 | .btn-default:active, 39 | .btn-default.active, 40 | .btn-default.focus, 41 | .btn-default:active, 42 | .btn-default:focus, 43 | .btn-default:hover, 44 | .open > .dropdown-toggle.btn-default { 45 | background-color: #5fbeaa !important; 46 | border: 1px solid #5fbeaa !important; 47 | } 48 | .btn-white, 49 | .btn-white:hover, 50 | .btn-white:focus, 51 | .btn-white:active, 52 | .btn-white.active, 53 | .btn-white.focus, 54 | .btn-white:active, 55 | .btn-white:focus, 56 | .btn-white:hover, 57 | .open > .dropdown-toggle.btn-white { 58 | border: 1px solid #eaeaea !important; 59 | background-color: #ffffff; 60 | color: #4c5667; 61 | } 62 | .btn-white:hover, 63 | .btn-white:hover:hover, 64 | .btn-white:focus:hover, 65 | .btn-white:active:hover, 66 | .btn-white.active:hover, 67 | .btn-white.focus:hover, 68 | .btn-white:active:hover, 69 | .btn-white:focus:hover, 70 | .btn-white:hover:hover, 71 | .open > .dropdown-toggle.btn-white:hover { 72 | background-color: #f9f9f9; 73 | } 74 | .btn-white:focus, 75 | .btn-white:hover:focus, 76 | .btn-white:focus:focus, 77 | .btn-white:active:focus, 78 | .btn-white.active:focus, 79 | .btn-white.focus:focus, 80 | .btn-white:active:focus, 81 | .btn-white:focus:focus, 82 | .btn-white:hover:focus, 83 | .open > .dropdown-toggle.btn-white:focus { 84 | background-color: #f9f9f9; 85 | } 86 | .btn-white:active, 87 | .btn-white:hover:active, 88 | .btn-white:focus:active, 89 | .btn-white:active:active, 90 | .btn-white.active:active, 91 | .btn-white.focus:active, 92 | .btn-white:active:active, 93 | .btn-white:focus:active, 94 | .btn-white:hover:active, 95 | .open > .dropdown-toggle.btn-white:active { 96 | background-color: #f9f9f9; 97 | } 98 | .btn-primary, 99 | .btn-primary:hover, 100 | .btn-primary:focus, 101 | .btn-primary:active, 102 | .btn-primary.active, 103 | .btn-primary.focus, 104 | .btn-primary:active, 105 | .btn-primary:focus, 106 | .btn-primary:hover, 107 | .open > .dropdown-toggle.btn-primary { 108 | background-color: #5d9cec !important; 109 | border: 1px solid #5d9cec !important; 110 | } 111 | .btn-success, 112 | .btn-success:hover, 113 | .btn-success:focus, 114 | .btn-success:active, 115 | .btn-success.active, 116 | .btn-success.focus, 117 | .btn-success:active, 118 | .btn-success:focus, 119 | .btn-success:hover, 120 | .open > .dropdown-toggle.btn-success { 121 | background-color: #81c868 !important; 122 | border: 1px solid #81c868 !important; 123 | } 124 | .btn-info, 125 | .btn-info:hover, 126 | .btn-info:focus, 127 | .btn-info:active, 128 | .btn-info.active, 129 | .btn-info.focus, 130 | .btn-info:active, 131 | .btn-info:focus, 132 | .btn-info:hover, 133 | .open > .dropdown-toggle.btn-info { 134 | background-color: #34d3eb !important; 135 | border: 1px solid #34d3eb !important; 136 | } 137 | 138 | .btn-danger, 139 | .btn-danger:active, 140 | .btn-danger:focus, 141 | .btn-danger:hover, 142 | .btn-danger.active, 143 | .btn-danger.focus, 144 | .btn-danger:active, 145 | .btn-danger:focus, 146 | .btn-danger:hover, 147 | .open > .dropdown-toggle.btn-danger { 148 | background-color: #f05050 !important; 149 | border: 1px solid #f05050 !important; 150 | } 151 | .btn-inverse, 152 | .btn-inverse:hover, 153 | .btn-inverse:focus, 154 | .btn-inverse:active, 155 | .btn-inverse.active, 156 | .btn-inverse.focus, 157 | .btn-inverse:active, 158 | .btn-inverse:focus, 159 | .btn-inverse:hover, 160 | .open > .dropdown-toggle.btn-inverse { 161 | background-color: #4c5667 !important; 162 | border: 1px solid #4c5667 !important; 163 | color: #ffffff; 164 | } 165 | .btn-purple, 166 | .btn-purple:hover, 167 | .btn-purple:focus, 168 | .btn-purple:active { 169 | background-color: #7266ba !important; 170 | border: 1px solid #7266ba !important; 171 | color: #ffffff; 172 | } 173 | .btn-pink, 174 | .btn-pink:hover, 175 | .btn-pink:focus, 176 | .btn-pink:active { 177 | background-color: #fb6d9d !important; 178 | border: 1px solid #fb6d9d !important; 179 | color: #ffffff; 180 | } 181 | .open > .dropdown-toggle.btn-primary.btn-custom, 182 | .open > .dropdown-toggle.btn-success.btn-custom, 183 | .open > .dropdown-toggle.btn-info.btn-custom, 184 | .open > .dropdown-toggle.btn-warning.btn-custom, 185 | .open > .dropdown-toggle.btn-danger.btn-custom, 186 | .open > .dropdown-toggle.btn-default.btn-custom { 187 | border-width: 2px !important; 188 | color: #ffffff !important; 189 | } 190 | .open > .dropdown-toggle.btn-white.btn-custom { 191 | border-width: 2px !important; 192 | } 193 | .btn-custom.btn-default { 194 | color: #5fbeaa !important; 195 | } 196 | .btn-custom.btn-primary { 197 | color: #5d9cec !important; 198 | } 199 | .btn-custom.btn-success { 200 | color: #81c868 !important; 201 | } 202 | .btn-custom.btn-info { 203 | color: #34d3eb !important; 204 | } 205 | .btn-custom.btn-warning { 206 | color: #ffbd4a !important; 207 | } 208 | .btn-custom.btn-danger { 209 | color: #f05050 !important; 210 | } 211 | .btn-custom.btn-inverse { 212 | color: #4c5667 !important; 213 | } 214 | .btn-custom.btn-purple { 215 | color: #7266ba !important; 216 | } 217 | 218 | .btn-custom.btn-white:hover, 219 | .btn-custom.btn-white:focus, 220 | .btn-custom.btn-white:active { 221 | color: #4c5667 !important; 222 | background-color: #f4f8fb !important; 223 | } 224 | .btn-custom.btn-pink { 225 | color: #fb6d9d !important; 226 | } 227 | .btn-rounded { 228 | border-radius: 2em !important; 229 | padding: 6px 20px; 230 | } 231 | .btn-rounded .btn-label { 232 | padding: 7px 15px 7px 20px; 233 | margin-left: -20px; 234 | } 235 | .btn-rounded .btn-label-right { 236 | margin-right: -20px; 237 | margin-left: 12px; 238 | } 239 | .btn-custom { 240 | -moz-border-radius: 2px; 241 | -moz-transition: all 400ms ease-in-out; 242 | -o-transition: all 400ms ease-in-out; 243 | -webkit-border-radius: 2px; 244 | -webkit-transition: all 400ms ease-in-out; 245 | background: transparent; 246 | background-color: transparent !important; 247 | -webkit-border-radius: 5px; 248 | border-radius: 5px; 249 | -moz-border-radius: 5px; 250 | background-clip: padding-box; 251 | border-width: 2px !important; 252 | font-weight: 600; 253 | transition: all 400ms ease-in-out; 254 | background-clip: inherit; 255 | } 256 | .btn-custom:hover { 257 | color: #ffffff !important; 258 | border-width: 2px !important; 259 | } 260 | .btn-custom:focus { 261 | color: #ffffff !important; 262 | border-width: 2px !important; 263 | } 264 | .btn-label { 265 | background: rgba(0, 0, 0, 0.05); 266 | display: inline-block; 267 | padding: 7px 15px; 268 | border-radius: 3px 0 0 3px; 269 | margin: -7px -13px; 270 | margin-right: 12px; 271 | } 272 | .btn-label-right { 273 | margin-left: 12px; 274 | margin-right: -13px; 275 | border-radius: 0px 3px 3px 0px; 276 | } 277 | .btn-group.open .dropdown-toggle { 278 | box-shadow: none; 279 | } 280 | 281 | .float-left { 282 | float: left !important; 283 | } 284 | 285 | .float-right { 286 | float: right !important; 287 | } 288 | 289 | .margin-bottom { 290 | margin-bottom: 1em; 291 | } 292 | 293 | .margin-top { 294 | margin-top: 1em; 295 | } 296 | 297 | .padding-right { 298 | padding-right: 15px; 299 | } 300 | 301 | .no-padding-right { 302 | padding-right: 0; 303 | } 304 | 305 | .no-margin-bottom { 306 | margin-bottom: 0; 307 | } 308 | 309 | .user { 310 | margin-top: 8px; 311 | margin-right: 10px; 312 | } 313 | 314 | /* Forms */ 315 | #invoice_status { 316 | margin-top: 23px; 317 | } 318 | 319 | .select-customer { 320 | margin-top: 10px; 321 | } 322 | 323 | .delete-row { 324 | float: left; 325 | margin-top: 4px; 326 | } 327 | 328 | .item-select { 329 | float: left; 330 | margin: 4px; 331 | } 332 | 333 | .item-input { 334 | float: left; 335 | width: 65%; 336 | margin-left: 10px; 337 | } 338 | 339 | .textarea { 340 | width: 100%; 341 | } 342 | 343 | .textarea textarea { 344 | width: 100%; 345 | padding: 10px; 346 | resize: none; 347 | } 348 | 349 | /* Other styles */ 350 | strong.shipping { 351 | margin-top: 4px; 352 | display: block; 353 | } 354 | 355 | .input-group.date .dropdown-menu{ 356 | display: block; 357 | } 358 | 359 | #sidebar { 360 | width: 200px; 361 | position: absolute; 362 | left: 0; 363 | top: 0; 364 | background: rgb(17,17,17); 365 | background: radial-gradient(circle, rgba(17,17,17,1) 15%, rgba(15,12,83,1) 95%, rgba(0,0,0,1) 99%); 366 | height: 100%; 367 | padding-top: 40px; 368 | z-index: 99999; 369 | } 370 | 371 | 372 | ul#menu-v, #menu-v ul 373 | { 374 | width:200px; /* Main Menu width */ 375 | border:1px solid rgba(190,190,190,0.3); 376 | list-style:none; margin:0; padding:0; 377 | z-index:9; 378 | top: 200px; 379 | } 380 | 381 | #menu-v li 382 | { 383 | margin:0; 384 | padding:0; 385 | position:relative; 386 | background-color: #0b0922; 387 | transition:background 0.5s; 388 | } 389 | #menu-v li:hover 390 | { 391 | background-color:rgba(0,0,0,0.9); 392 | } 393 | 394 | #menu-v a 395 | { 396 | font: normal 14px Arial; 397 | border-top: 1px solid rgba(190,190,190,0.3); 398 | display:block; 399 | color:#ccc; 400 | text-decoration:none; 401 | line-height:30px; 402 | padding-left:22px; 403 | position:relative; 404 | } 405 | 406 | #menu-v li:first-child a 407 | { 408 | border-top:0; 409 | } 410 | 411 | #menu-v a.arrow::after{ 412 | content:''; 413 | position:absolute; 414 | display:inline; 415 | top:50%; 416 | margin-top:-4px; 417 | right:8px; 418 | border-width:4px; 419 | border-style:solid; 420 | border-color:transparent transparent transparent white; 421 | transition:border-color 0.5s; 422 | } 423 | 424 | #menu-v li a.arrow:hover::after 425 | { 426 | border-color:transparent transparent transparent #CCCCCC; 427 | } 428 | 429 | /*Sub level menu items 430 | ---------------------------------------*/ 431 | #menu-v li ul 432 | { 433 | min-width:180px; /* Sub level menu min width */ 434 | position:absolute; 435 | display:none; 436 | left:100%; 437 | top:50%; 438 | transform:translateY(-50%); 439 | } 440 | 441 | #menu-v li:hover > ul 442 | { 443 | display:block; 444 | } 445 | 446 | 447 | #pdf{ 448 | max-width: 800px; 449 | height: 1100px; 450 | padding: 30px; 451 | } 452 | 453 | .invoice_product_desc { 454 | float: left; 455 | width: 95%; 456 | margin-left: 10px; 457 | } 458 | 459 | .invoice { 460 | position: relative; 461 | background-color: #FFF; 462 | min-height: 680px; 463 | padding: 15px 464 | } 465 | 466 | .invoice header { 467 | padding: 10px 0; 468 | margin-bottom: 20px; 469 | border-bottom: 1px solid #3989c6 470 | } 471 | 472 | .invoice .company-details { 473 | text-align: right 474 | } 475 | 476 | .invoice .company-details .name { 477 | margin-top: 0; 478 | margin-bottom: 0 479 | } 480 | 481 | .invoice .contacts { 482 | margin-bottom: 20px 483 | } 484 | 485 | .invoice .invoice-to { 486 | text-align: left 487 | } 488 | 489 | .invoice .invoice-to .to { 490 | margin-top: 0; 491 | margin-bottom: 0 492 | } 493 | 494 | .invoice .invoice-details { 495 | text-align: right 496 | } 497 | 498 | .invoice .invoice-details .invoice-id { 499 | margin-top: 0; 500 | color: #3989c6 501 | } 502 | 503 | .invoice main { 504 | padding-bottom: 50px 505 | } 506 | 507 | .invoice main .thanks { 508 | margin-top: -100px; 509 | font-size: 1.5em; 510 | margin-bottom: 50px 511 | } 512 | 513 | .invoice main .notices { 514 | padding-left: 6px; 515 | border-left: 6px solid #3989c6 516 | } 517 | 518 | .invoice main .notices .notice { 519 | font-size: 1.2em 520 | } 521 | 522 | .invoice table { 523 | width: 100%; 524 | border-collapse: collapse; 525 | border-spacing: 0; 526 | margin-bottom: 20px 527 | } 528 | 529 | .invoice table td,.invoice table th { 530 | padding: 12px; 531 | background: #eee; 532 | border-bottom: 1px solid #fff 533 | } 534 | 535 | .invoice table th { 536 | white-space: nowrap; 537 | font-weight: 400; 538 | font-size: 14px 539 | } 540 | 541 | .invoice table td h3 { 542 | margin: 0; 543 | font-weight: 400; 544 | color: #3989c6; 545 | font-size: 1em 546 | } 547 | 548 | .invoice table .qty,.invoice table .total,.invoice table .unit { 549 | text-align: right; 550 | font-size: 1em 551 | } 552 | 553 | .invoice table .no { 554 | color: #fff; 555 | font-size: 1em; 556 | background: #3989c6 557 | } 558 | 559 | .invoice table .unit { 560 | background: #ddd 561 | } 562 | 563 | .invoice table .total { 564 | background: #3989c6; 565 | color: #fff 566 | } 567 | 568 | .invoice table tbody tr:last-child td { 569 | border: none 570 | } 571 | 572 | .invoice table tfoot td { 573 | background: 0 0; 574 | border-bottom: none; 575 | white-space: nowrap; 576 | text-align: right; 577 | padding: 10px; 578 | font-size: 1em; 579 | border-top: 1px solid #aaa 580 | } 581 | 582 | .invoice table tfoot tr:first-child td { 583 | border-top: none 584 | } 585 | 586 | .invoice table tfoot tr:last-child td { 587 | color: #3989c6; 588 | font-size: 1.2em; 589 | border-top: 1px solid #3989c6 590 | } 591 | 592 | .invoice table tfoot tr td:first-child { 593 | border: none 594 | } 595 | 596 | .invoice footer { 597 | width: 100%; 598 | text-align: center; 599 | color: #777; 600 | border-top: 1px solid #aaa; 601 | padding: 8px 0 602 | } 603 | 604 | @media print { 605 | .invoice { 606 | font-size: 11px!important; 607 | overflow: hidden!important 608 | } 609 | 610 | .invoice footer { 611 | position: absolute; 612 | bottom: 10px; 613 | page-break-after: always 614 | } 615 | 616 | .invoice>div:last-child { 617 | page-break-before: always 618 | } 619 | } 620 | 621 | #inner { 622 | margin: 0 250px; 623 | } 624 | 625 | .simulate { 626 | 627 | } 628 | 629 | .page { 630 | float: left; 631 | min-height: 100%; 632 | padding-top: 30px; 633 | } 634 | 635 | #current_img img, #logo img { 636 | max-width: 100px; 637 | } 638 | 639 | #vat_line { 640 | display: none; 641 | } 642 | 643 | .nobr { 644 | white-space:nowrap; 645 | } 646 | 647 | .swal2-popup { 648 | font-size: 1.6rem !important; 649 | } 650 | 651 | 652 | #create .panel-heading { 653 | color: #fff; 654 | background-color: #f0ad4e; 655 | border-color: #eea236; 656 | } 657 | 658 | 659 | #create .panel, 660 | .form-control { 661 | border-color: #dbc29e; 662 | } 663 | 664 | #invoice_notes, #email_msg { 665 | height: 100px; 666 | border-radius: 4px; 667 | } 668 | 669 | 670 | #create_invoice { 671 | padding-bottom: 60px; 672 | border-bottom: 1px solid #dbc29e; 673 | border-radius: 8px; 674 | } 675 | 676 | .offline { 677 | font-weight: 700; 678 | color: #EA4335; 679 | } 680 | 681 | .online { 682 | font-weight: 700; 683 | color: #5cb85c; 684 | } 685 | 686 | #year_area { 687 | height: 400px; 688 | width: 100%; 689 | border: 1px solid #ddd; 690 | margin-bottom: 50px; 691 | margin-top: 40px; 692 | padding-top: 20px; 693 | } 694 | 695 | .stats h4 { 696 | display: block; 697 | background-color: rgb(247, 163, 92); 698 | color: #fff; 699 | text-transform: uppercase; 700 | font-size: 14px; 701 | padding: 5px; 702 | text-align: center; 703 | border-bottom: 1px solid rgb(247, 163, 92); 704 | margin: 0; 705 | } 706 | 707 | .stats .numbers{ 708 | font-size: 42px; 709 | text-align: center; 710 | height: 100px; 711 | padding-top: 20px; 712 | border: 1px solid rgb(247, 163, 92); 713 | border-bottom: 1px solid #fff; 714 | color: #1AADCE; 715 | } 716 | 717 | #pie { 718 | height: 300px; 719 | width: 100%; 720 | margin-top: 40px; 721 | } 722 | 723 | 724 | .stats .values{ 725 | display: block; 726 | color: #fff; 727 | text-transform: uppercase; 728 | font-size: 16px; 729 | padding: 5px; 730 | text-align: center; 731 | background-color: #1AADCE; 732 | border-bottom: 1px solid #fff; 733 | margin: 0; 734 | } 735 | 736 | #loading { 737 | background: rgb(221,221,221); 738 | background: radial-gradient(circle, rgba(153,153,153,1) 0%, rgba(221,221,221,1) 100%); 739 | opacity: 0.4; 740 | position: absolute; 741 | height: 100%; 742 | width: 100%; 743 | z-index: 9999; 744 | overflow: hidden; 745 | display: none; 746 | } 747 | 748 | #sending { 749 | width: 300px; 750 | z-index: 999; 751 | margin-left: auto; 752 | margin-right: auto; 753 | position: absolute; 754 | top: 0; 755 | left: 45%; 756 | display: none; 757 | } 758 | 759 | #sending img { 760 | max-width: 170px; 761 | } 762 | 763 | #smtp_settings { 764 | display: none; 765 | } 766 | 767 | #download { 768 | margin: 10px; 769 | border: 1px solid #0F0D41; 770 | padding: 10px; 771 | color: #ccc; 772 | display: none; 773 | } 774 | 775 | ul { 776 | display: block; 777 | list-style-type: disc; 778 | margin-block-start: 1em; 779 | margin-block-end: 1em; 780 | margin-inline-start: 0px; 781 | margin-inline-end: 0px; 782 | padding-inline-start: 10px; 783 | } 784 | 785 | .btn-custom.btn-white { 786 | color: #4c5667 !important; 787 | } 788 | 789 | #progress { 790 | margin: 10px; 791 | width: 100%; 792 | border: 1px solid #222; 793 | } 794 | 795 | #bar { 796 | padding: 4px; 797 | background-color: #2B619B; 798 | width: 0px; 799 | text-align: center; 800 | color: #fff; 801 | } 802 | 803 | #install, #progress, #starting { 804 | display: none; 805 | } 806 | 807 | #wrapper { 808 | height: 100vh; 809 | overflow-y: scroll; 810 | } -------------------------------------------------------------------------------- /assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /assets/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/assets/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /assets/images/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/assets/images/icon.icns -------------------------------------------------------------------------------- /assets/images/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/assets/images/icon.ico -------------------------------------------------------------------------------- /assets/images/sending.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/assets/images/sending.gif -------------------------------------------------------------------------------- /assets/plugins/dataTables/buttons.print.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Print button for Buttons and DataTables. 3 | 2016 SpryMedia Ltd - datatables.net/license 4 | */ 5 | (function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(e){return c(e,window,document)}):"object"===typeof exports?module.exports=function(e,a){e||(e=window);a&&a.fn.dataTable||(a=require("datatables.net")(e,a).$);a.fn.dataTable.Buttons||require("datatables.net-buttons")(e,a);return c(a,e,e.document)}:c(jQuery,window,document)})(function(c,e,a,q){var k=c.fn.dataTable,d=a.createElement("a"),p=function(b){d.href=b;b=d.host;-1===b.indexOf("/")&& 6 | 0!==d.pathname.indexOf("/")&&(b+="/");return d.protocol+"//"+b+d.pathname+d.search};k.ext.buttons.print={className:"buttons-print",text:function(b){return b.i18n("buttons.print","Print")},action:function(b,a,d,g){b=a.buttons.exportData(c.extend({decodeEntities:!1},g.exportOptions));d=a.buttons.exportInfo(g);var k=a.columns(g.exportOptions.columns).flatten().map(function(b){return a.settings()[0].aoColumns[a.column(b).index()].sClass}).toArray(),m=function(b,a){for(var d="",c=0,e=b.length;c"+(null===b[c]||b[c]===q?"":b[c])+"";return d+""},h='';g.header&&(h+=""+m(b.header,"th")+"");h+="";for(var n=0,r=b.body.length;n";g.footer&&b.footer&&(h+=""+m(b.footer,"th")+"");h+="
";var f=e.open("","");f.document.close();var l=""+d.title+"";c("style, link").each(function(){var b=l,a=c(this).clone()[0]; 8 | "link"===a.nodeName.toLowerCase()&&(a.href=p(a.href));l=b+a.outerHTML});try{f.document.head.innerHTML=l}catch(t){c(f.document.head).html(l)}f.document.body.innerHTML="

"+d.title+"

"+(d.messageTop||"")+"
"+h+"
"+(d.messageBottom||"")+"
";c(f.document.body).addClass("dt-print-view");c("img",f.document.body).each(function(b,a){a.setAttribute("src",p(a.getAttribute("src")))});g.customize&&g.customize(f,g,a);b=function(){g.autoPrint&&(f.print(),f.close())};navigator.userAgent.match(/Trident\/\d.\d/)? 9 | b():f.setTimeout(b,1E3)},title:"*",messageTop:"*",messageBottom:"*",exportOptions:{},header:!0,footer:!1,autoPrint:!0,customize:null};return k.Buttons}); 10 | -------------------------------------------------------------------------------- /assets/plugins/dataTables/dataTables.bootstrap.min.css: -------------------------------------------------------------------------------- 1 | table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:8px;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:8px;right:8px;display:block;font-family:'Glyphicons Halflings';opacity:0.5}table.dataTable thead .sorting:after{opacity:0.2;content:"\e150"}table.dataTable thead .sorting_asc:after{content:"\e155"}table.dataTable thead .sorting_desc:after{content:"\e156"}table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{color:#eee}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody>table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody>table>thead .sorting:after,div.dataTables_scrollBody>table>thead .sorting_asc:after,div.dataTables_scrollBody>table>thead .sorting_desc:after{display:none}div.dataTables_scrollBody>table>tbody>tr:first-child>th,div.dataTables_scrollBody>table>tbody>tr:first-child>td{border-top:none}div.dataTables_scrollFoot>.dataTables_scrollFootInner{box-sizing:content-box}div.dataTables_scrollFoot>.dataTables_scrollFootInner>table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-condensed>thead>tr>th{padding-right:20px}table.dataTable.table-condensed .sorting:after,table.dataTable.table-condensed .sorting_asc:after,table.dataTable.table-condensed .sorting_desc:after{top:6px;right:6px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0} 2 | -------------------------------------------------------------------------------- /assets/plugins/dataTables/dataTables.buttons.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Buttons for DataTables 1.6.1 3 | ©2016-2019 SpryMedia Ltd - datatables.net/license 4 | */ 5 | (function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(u){return d(u,window,document)}):"object"===typeof exports?module.exports=function(u,t){u||(u=window);t&&t.fn.dataTable||(t=require("datatables.net")(u,t).$);return d(t,u,u.document)}:d(jQuery,window,document)})(function(d,u,t,p){function y(a){a=new m.Api(a);var b=a.init().buttons||m.defaults.buttons;return(new n(a,b)).container()}var m=d.fn.dataTable,B=0,C=0,q=m.ext.buttons,n=function(a,b){if(!(this instanceof 6 | n))return function(b){return(new n(b,a)).container()};"undefined"===typeof b&&(b={});!0===b&&(b={});d.isArray(b)&&(b={buttons:b});this.c=d.extend(!0,{},n.defaults,b);b.buttons&&(this.c.buttons=b.buttons);this.s={dt:new m.Api(a),buttons:[],listenKeys:"",namespace:"dtb"+B++};this.dom={container:d("<"+this.c.dom.container.tag+"/>").addClass(this.c.dom.container.className)};this._constructor()};d.extend(n.prototype,{action:function(a,b){a=this._nodeToButton(a);if(b===p)return a.conf.action;a.conf.action= 7 | b;return this},active:function(a,b){var c=this._nodeToButton(a);a=this.c.dom.button.active;c=d(c.node);if(b===p)return c.hasClass(a);c.toggleClass(a,b===p?!0:b);return this},add:function(a,b){var c=this.s.buttons;if("string"===typeof b){b=b.split("-");var e=this.s;c=0;for(var d=b.length-1;c"),l.conf._collection=l.collection,this._expandButton(l.buttons,l.conf.buttons,!0,e)),r.init&&r.init.call(g.button(l.node),g,d(l.node),r),f++)}}},_buildButton:function(a,b){var c=this.c.dom.button,e=this.c.dom.buttonLiner,g=this.c.dom.collection,f=this.s.dt,h=function(b){return"function"===typeof b?b(f,l,a):b};b&&g.button&&(c=g.button);b&&g.buttonLiner&&(e=g.buttonLiner);if(a.available&&!a.available(f,a))return!1;var k=function(a,b,c,e){e.action.call(b.button(c),a,b,c,e);d(b.table().node()).triggerHandler("buttons-action.dt", 14 | [b.button(c),b,c,e])};g=a.tag||c.tag;var r=a.clickBlurs===p?!0:a.clickBlurs,l=d("<"+g+"/>").addClass(c.className).attr("tabindex",this.s.dt.settings()[0].iTabIndex).attr("aria-controls",this.s.dt.table().node().id).on("click.dtb",function(b){b.preventDefault();!l.hasClass(c.disabled)&&a.action&&k(b,f,l,a);r&&l.blur()}).on("keyup.dtb",function(b){13===b.keyCode&&!l.hasClass(c.disabled)&&a.action&&k(b,f,l,a)});"a"===g.toLowerCase()&&l.attr("href","#");"button"===g.toLowerCase()&&l.attr("type","button"); 15 | e.tag?(g=d("<"+e.tag+"/>").html(h(a.text)).addClass(e.className),"a"===e.tag.toLowerCase()&&g.attr("href","#"),l.append(g)):l.html(h(a.text));!1===a.enabled&&l.addClass(c.disabled);a.className&&l.addClass(a.className);a.titleAttr&&l.attr("title",h(a.titleAttr));a.attr&&l.attr(a.attr);a.namespace||(a.namespace=".dt-button-"+C++);e=(e=this.c.dom.buttonContainer)&&e.tag?d("<"+e.tag+"/>").addClass(e.className).append(l):l;this._addKey(a);this.c.buttonCreated&&(e=this.c.buttonCreated(a,e));return{conf:a, 16 | node:l.get(0),inserter:e,buttons:[],inCollection:b,collection:null}},_nodeToButton:function(a,b){b||(b=this.s.buttons);for(var c=0,e=b.length;c").addClass("dt-button-collection").addClass(g.collectionLayout).css("display","none");a=d(a).addClass(g.contentClassName).attr("role","menu").appendTo(c);f.attr("aria-expanded","true");f.parents("body")[0]!==t.body&&(f=t.body.lastChild);g.collectionTitle&&c.prepend('
'+g.collectionTitle+"
");c.insertAfter(f).fadeIn(g.fade); 22 | var k=d(b.table().container());e=c.css("position");"dt-container"===g.align&&(f=f.parent(),c.css("width",k.width()));if("absolute"===e){e=f.position();c.css({top:e.top+f.outerHeight(),left:e.left});var r=c.outerHeight(),l=c.outerWidth(),w=k.offset().top+k.height();w=e.top+f.outerHeight()+r-w;var D=e.top-r,m=k.offset().top;r=e.top-r-5;(w>m-D||g.dropup)&&-rk&&c.css("left",e.left-(r-k));k=f.offset().left+l;k>d(u).width()&&c.css("left",e.left-(k-d(u).width()))}else e=c.height()/2,e>d(u).height()/2&&(e=d(u).height()/2),c.css("marginTop",-1*e);g.background&&n.background(!0,g.backgroundClassName,g.fade,f);d("div.dt-button-background").on("click.dtb-collection",function(){});d("body").on("click.dtb-collection",function(b){var c=d.fn.addBack?"addBack":"andSelf";d(b.target).parents()[c]().filter(a).length||h()}).on("keyup.dtb-collection",function(a){27=== 24 | a.keyCode&&h()});g.autoClose&&setTimeout(function(){b.on("buttons-action.b-internal",function(a,b,c,e){e[0]!==f[0]&&h()})},0)}});n.background=function(a,b,c,e){c===p&&(c=400);e||(e=t.body);a?d("
").addClass(b).css("display","none").insertAfter(e).stop().fadeIn(c):d("div."+b).stop().fadeOut(c,function(){d(this).removeClass(b).remove()})};n.instanceSelector=function(a,b){if(a===p||null===a)return d.map(b,function(a){return a.inst});var c=[],e=d.map(b,function(a){return a.name}),g=function(a){if(d.isArray(a))for(var f= 25 | 0,k=a.length;f"+a+"":"";d('
').html(a).append(d("
")["string"=== 37 | typeof b?"html":"append"](b)).css("display","none").appendTo("body").fadeIn();c!==p&&0!==c&&(v=setTimeout(function(){e.buttons.info(!1)},c));this.on("destroy.btn-info",function(){e.buttons.info(!1)});return this});m.Api.register("buttons.exportData()",function(a){if(this.context.length)return E(new m.Api(this.context[0]),a)});m.Api.register("buttons.exportInfo()",function(a){a||(a={});var b=a;var c="*"===b.filename&&"*"!==b.title&&b.title!==p&&null!==b.title&&""!==b.title?b.title:b.filename;"function"=== 38 | typeof c&&(c=c());c===p||null===c?c=null:(-1!==c.indexOf("*")&&(c=d.trim(c.replace("*",d("head > title").text()))),c=c.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g,""),(b=x(b.extension))||(b=""),c+=b);b=x(a.title);b=null===b?null:-1!==b.indexOf("*")?b.replace("*",d("head > title").text()||"Exported data"):b;return{filename:c,title:b,messageTop:z(this,a.message||a.messageTop,"top"),messageBottom:z(this,a.messageBottom,"bottom")}});var x=function(a){return null===a||a===p?null:"function"===typeof a? 39 | a():a},z=function(a,b,c){b=x(b);if(null===b)return null;a=d("caption",a.table().container()).eq(0);return"*"===b?a.css("caption-side")!==c?null:a.length?a.text():"":b},A=d(" 123 | 124 |
125 | 126 | 127 | 128 | 129 | 130 |
131 |
132 |
133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 |
141 | 149 | 150 |
151 | 152 | 153 | 154 | 155 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /docs/js/jquery.custom.js: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------ 2 | jQuery document ready 3 | -------------------------------------------------------------------*/ 4 | $(document).ready(function () { 5 | "use strict"; 6 | if (jQuery.isFunction(jQuery.fn.paroller) && screen.width > 800 ) { 7 | $("[data-paroller-factor]").paroller(); 8 | } 9 | 10 | // Pricing switcher button 11 | $(".switcher__button").on('click', function(e) { 12 | $(".switcher__button").toggleClass('switcher__button--enabled'); 13 | $(".pricing__value").removeClass('pricing__value--hidden'); 14 | $(".pricing__value").toggleClass('pricing__value--show pricing__value--hide'); 15 | }); 16 | 17 | 18 | // Modal login and signup 19 | $('.modal-toggle').on('click', function(e) { 20 | e.preventDefault(); 21 | var modalopen = $(this).data("openpopup"); 22 | $('.modal--'+modalopen).toggleClass('modal--visible'); 23 | var modaltype = $(this).data("popup"); 24 | $('.modal__content--'+modaltype).toggleClass('modal__content--visible'); 25 | $('.modal__switch').on('click', function(e) { 26 | $('.modal__content').removeClass('modal__content--visible'); 27 | var modaltypeb = $(this).data("popup"); 28 | $('.modal__content--'+modaltypeb).toggleClass('modal__content--visible'); 29 | }); 30 | }); 31 | 32 | $('.modal__overlay--toggle').on('click', function(e) { 33 | e.preventDefault(); 34 | $('.modal').removeClass('modal--visible'); 35 | $('.modal__content').removeClass('modal__content--visible'); 36 | }); 37 | 38 | 39 | }); -------------------------------------------------------------------------------- /docs/js/jquery.paroller.min.js: -------------------------------------------------------------------------------- 1 | !function(r){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=r(require("jquery")):r(jQuery)}(function($){"use strict";var r={bgVertical:function(r,t){return r.css({"background-position":"center "+-t+"px"})},bgHorizontal:function(r,t){return r.css({"background-position":-t+"px center"})},vertical:function(r,t,o){return"none"===o?o="":!0,r.css({"-webkit-transform":"translateY("+t+"px)"+o,"-moz-transform":"translateY("+t+"px)"+o,transform:"translateY("+t+"px)"+o,transition:"transform linear","will-change":"transform"})},horizontal:function(r,t,o){return"none"===o?o="":!0,r.css({"-webkit-transform":"translateX("+t+"px)"+o,"-moz-transform":"translateX("+t+"px)"+o,transform:"translateX("+t+"px)"+o,transition:"transform linear","will-change":"transform"})}};$.fn.paroller=function(t){var o=$(window).height(),n=$(document).height(),t=$.extend({factor:0,type:"background",direction:"vertical"},t);return this.each(function(){var a=!1,e=$(this),i=e.offset().top,c=e.outerHeight(),l=e.data("paroller-factor"),s=e.data("paroller-type"),u=e.data("paroller-direction"),f=l?l:t.factor,d=s?s:t.type,h=u?u:t.direction,p=Math.round(i*f),g=Math.round((i-o/2+c)*f),m=e.css("transform");"background"==d?"vertical"==h?r.bgVertical(e,p):"horizontal"==h&&r.bgHorizontal(e,p):"foreground"==d&&("vertical"==h?r.vertical(e,g,m):"horizontal"==h&&r.horizontal(e,g,m));var b=function(){a=!1};$(window).on("scroll",function(){if(!a){var t=$(this).scrollTop();n=$(document).height(),p=Math.round((i-t)*f),g=Math.round((i-o/2+c-t)*f),"background"==d?"vertical"==h?r.bgVertical(e,p):"horizontal"==h&&r.bgHorizontal(e,p):"foreground"==d&&n>=t&&("vertical"==h?r.vertical(e,g,m):"horizontal"==h&&r.horizontal(e,g,m)),window.requestAnimationFrame(b),a=!0}}).trigger("scroll")})}}); -------------------------------------------------------------------------------- /docs/js/menu.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | "use strict"; 3 | function navScroll(){ 4 | var window_top = $(window).scrollTop(); 5 | var div_top = $('body').offset().top; 6 | if (window_top > div_top) { 7 | $('.header').addClass('header--sticky'); 8 | $('.header__menu ul ul').addClass('submenu-header-sticky'); 9 | } else { 10 | $('.header').removeClass('header--sticky'); 11 | $('.header__menu ul ul').removeClass('submenu-header-sticky'); 12 | } 13 | } 14 | $(window).scroll(function() { 15 | navScroll(); 16 | }); 17 | navScroll(); 18 | 19 | $(document).on("scroll", onScroll); 20 | 21 | var delegate = function(criteria, listener) { 22 | return function(e) { 23 | var el = e.target; 24 | do { 25 | if (!criteria(el)) continue; 26 | e.delegateTarget = el; 27 | listener.apply(this, arguments); 28 | return; 29 | } while( (el = el.parentNode) ); 30 | }; 31 | }; 32 | var toolbar = document.querySelector(".header__menu"); 33 | var buttonsFilter = function(elem) { return elem.classList && elem.classList.contains("header-link"); }; 34 | var buttonHandler = function(e) { 35 | var button = e.delegateTarget; 36 | if(!button.classList.contains("active")){ 37 | button.classList.add("active"); 38 | var target = button.hash; 39 | var $target = $(target); 40 | 41 | $('html, body').stop().animate({ 42 | 'scrollTop': $target.offset().top 43 | }, 600, 'swing', function () { 44 | window.location.hash = target; 45 | $(document).on("scroll", onScroll); 46 | }); 47 | } 48 | else { 49 | button.classList.remove("active"); 50 | } 51 | }; 52 | toolbar.addEventListener("click", delegate(buttonsFilter, buttonHandler)); 53 | 54 | function onScroll(event){ 55 | 56 | var scrollPos = $(document).scrollTop(); 57 | $('.header__menu ul li a').each(function () { 58 | var currLink = $(this); 59 | var refElement = $(currLink.attr("href")); 60 | if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) { 61 | $('.header__menu ul li a').removeClass("selected"); 62 | currLink.addClass("active"); 63 | } 64 | else{ 65 | currLink.removeClass("active"); 66 | } 67 | }); 68 | } 69 | 70 | $.fn.menumaker = function(options) { 71 | 72 | var cssmenu = $(this), settings = $.extend({ 73 | title: "Menu", 74 | format: "dropdown", 75 | sticky: false 76 | }, options); 77 | 78 | return this.each(function() { 79 | cssmenu.prepend(''); 80 | $(this).find(".menu-button").on('click', function(){ 81 | $(this).parent().parent().parent().toggleClass('menu-open'); 82 | 83 | var mainmenu = $(this).next('ul'); 84 | mainmenu.toggleClass('open'); 85 | if (mainmenu.hasClass('open')) { 86 | mainmenu.show(); 87 | } 88 | else { 89 | mainmenu.hide(); 90 | } 91 | $('.header__menu ul a[href^="#"]').on('click', function (e) { 92 | $('.header__menu ul').removeClass('open'); 93 | $('.header__menu ul').hide(); 94 | $('.header').removeClass('menu-open'); 95 | }); 96 | }); 97 | 98 | var multiTg = function() { 99 | cssmenu.find(".menu-item-has-children").prepend(''); 100 | cssmenu.find('.submenu-button').on('click', function() { 101 | $(this).toggleClass('submenu-opened'); 102 | if ($(this).siblings('ul').hasClass('open')) { 103 | $(this).siblings('ul').removeClass('open').hide(); 104 | } 105 | else { 106 | $(this).siblings('ul').addClass('open').show(); 107 | } 108 | }); 109 | }; 110 | 111 | if (settings.format === 'multitoggle') multiTg(); 112 | else cssmenu.addClass('dropdown'); 113 | 114 | if (settings.sticky === true) cssmenu.addClass('sticky'); 115 | 116 | 117 | }); 118 | }; 119 | 120 | $(".header__menu").menumaker({ 121 | format: "multitoggle", 122 | sticky: true 123 | }); 124 | 125 | }); 126 | 127 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OfflineInvoicing", 3 | "version": "0.1.1", 4 | "description": "Offline Invoicing software for Windows.", 5 | "author": "Offline Invoicing", 6 | "private": true, 7 | "main": "start.js", 8 | "dependencies": { 9 | "electron": ">=7.2.4", 10 | "electron-context-menu": "^0.15.1", 11 | "electron-download-manager": "^2.1.2", 12 | "electron-packager": "^14.2.1", 13 | "electron-pdf-window": "^1.0.12", 14 | "electron-store": "^5.1.0", 15 | "electron-wix-msi": "^2.2.0", 16 | "file-saver": "^2.0.2", 17 | "highcharts": "^8.0.0", 18 | "html2canvas": "^1.0.0-rc.5", 19 | "html2pdf.js": "^0.9.1", 20 | "is-port-reachable": "^3.0.0", 21 | "jquery": "^3.4.1", 22 | "jspdf": "^1.5.3", 23 | "nedb": "^1.8.0", 24 | "nodemailer": "^6.4.2", 25 | "nodemon": "^1.14.12", 26 | "path": "^0.12.7", 27 | "sweetalert2": "^9.5.4" 28 | }, 29 | "scripts": { 30 | "electron": "cross-env NODE_ENV=dev nodemon --exec \"\"electron .\"\"", 31 | "electron-build": "electron-builder", 32 | "package-win": "electron-packager . OfflineInvoicing --overwrite --asar=false --platform=win32 --arch=x64 --icon=assets/images/icon.ico --prune=true --out=release-builds --version-string.ProductName=\"OfflineInvoicing\"", 33 | "setup": "electron-installer-windows --src release-builds/OfflineInvoicing-win32-x64/ --dest installers/" 34 | }, 35 | "browserslist": { 36 | "production": [ 37 | ">0.2%", 38 | "not dead", 39 | "not op_mini all" 40 | ], 41 | "development": [ 42 | "last 1 chrome version", 43 | "last 1 firefox version", 44 | "last 1 safari version" 45 | ] 46 | }, 47 | "devDependencies": { 48 | "cross-env": "^6.0.3", 49 | "electron-builder": "^21.2.0", 50 | "electron-installer-windows": "^3.0.0", 51 | "electron-is-dev": "^1.1.0", 52 | "nodemon": "^1.19.3" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /screenshots/create_invoice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/screenshots/create_invoice.png -------------------------------------------------------------------------------- /screenshots/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/screenshots/dashboard.png -------------------------------------------------------------------------------- /screenshots/invoices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/screenshots/invoices.png -------------------------------------------------------------------------------- /screenshots/pdf_invoice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tngoman/Offline_Invoicing/18d4701aefd20f44054f9a8e2e939e185f03bd85/screenshots/pdf_invoice.png -------------------------------------------------------------------------------- /setupEvents.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron') 2 | const app = electron.app 3 | 4 | module.exports = { 5 | handleSquirrelEvent: function() { 6 | if (process.argv.length === 1) { 7 | return false; 8 | } 9 | 10 | const ChildProcess = require('child_process'); 11 | const path = require('path'); 12 | 13 | const appFolder = path.resolve(process.execPath, '..'); 14 | const rootAtomFolder = path.resolve(appFolder, '..'); 15 | const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe')); 16 | const exeName = path.basename(process.execPath); 17 | const spawn = function(command, args) { 18 | let spawnedProcess, error; 19 | 20 | try { 21 | spawnedProcess = ChildProcess.spawn(command, args, {detached: true}); 22 | } catch (error) {} 23 | 24 | return spawnedProcess; 25 | }; 26 | 27 | const spawnUpdate = function(args) { 28 | return spawn(updateDotExe, args); 29 | }; 30 | 31 | const squirrelEvent = process.argv[1]; 32 | switch (squirrelEvent) { 33 | case '--squirrel-install': 34 | case '--squirrel-updated': 35 | // Optionally do things such as: 36 | // - Add your .exe to the PATH 37 | // - Write to the registry for things like file associations and 38 | // explorer context menus 39 | 40 | // Install desktop and start menu shortcuts 41 | spawnUpdate(['--createShortcut', exeName]); 42 | 43 | setTimeout(app.quit, 1000); 44 | return true; 45 | 46 | case '--squirrel-uninstall': 47 | // Undo anything you did in the --squirrel-install and 48 | // --squirrel-updated handlers 49 | 50 | // Remove desktop and start menu shortcuts 51 | spawnUpdate(['--removeShortcut', exeName]); 52 | 53 | setTimeout(app.quit, 1000); 54 | return true; 55 | 56 | case '--squirrel-obsolete': 57 | // This is called on the outgoing version of your app before 58 | // we update to the new version - it's the opposite of 59 | // --squirrel-updated 60 | 61 | app.quit(); 62 | return true; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /start.js: -------------------------------------------------------------------------------- 1 | const setupEvents = require('./setupEvents') 2 | if (setupEvents.handleSquirrelEvent()) { 3 | return; 4 | } 5 | 6 | 7 | const {app, BrowserWindow, ipcMain} = require('electron'); 8 | const path = require('path') 9 | const DownloadManager = require("electron-download-manager"); 10 | 11 | 12 | let mainWindow; 13 | 14 | function createWindow() { 15 | mainWindow = new BrowserWindow({ 16 | width: 1500, 17 | height: 1200, 18 | frame: false, 19 | minWidth: 1200, 20 | minHeight: 750, 21 | webPreferences: { 22 | nodeIntegration: true, 23 | plugins: true, 24 | webviewTag: true 25 | }, 26 | 27 | }); 28 | 29 | 30 | 31 | mainWindow.maximize(); 32 | mainWindow.show(); 33 | 34 | mainWindow.loadURL( 35 | `file://${path.join(__dirname, 'index.html')}` 36 | ) 37 | 38 | mainWindow.on('closed', () => { 39 | mainWindow = null 40 | }); 41 | 42 | } 43 | 44 | 45 | app.on('ready', createWindow) 46 | 47 | app.on('window-all-closed', () => { 48 | if (process.platform !== 'darwin') { 49 | app.quit() 50 | } 51 | }) 52 | 53 | app.on('activate', () => { 54 | if (mainWindow === null) { 55 | createWindow() 56 | } 57 | }) 58 | 59 | DownloadManager.register({ 60 | downloadFolder: app.getPath("downloads") + "/OfflineInvoicing" 61 | }); 62 | 63 | 64 | ipcMain.on('app-quit', (evt, arg) => { 65 | app.quit() 66 | }) 67 | 68 | 69 | ipcMain.on('app-reload', (event, arg) => { 70 | mainWindow.reload(); 71 | }); 72 | 73 | --------------------------------------------------------------------------------