Compare commits

...

36 Commits

Author SHA1 Message Date
Katja Lutz 1119f7b0b1 chore(release): 1.3.0 2 years ago
Katja Lutz be3d1888b3 fix: check for proper error message to silent common typer-js resume bug 2 years ago
Katja Lutz 6c801637f6 feat: implement like button
closes issue #18
2 years ago
Katja Lutz 153a86ab59 chore: implement server onExit utility 2 years ago
Katja Lutz f4dd2cdb7f feat: reset lastSaved time after document load 2 years ago
Katja Lutz 2ffdc401f1 feat: implement logo delete button 2 years ago
Katja Lutz f54b309b65 chore: support jsx element as TextInput suffix 2 years ago
Katja Lutz 24e82ace96 feat: implement addressLayout setting and optimize address layouts for print
closes issue #14
2 years ago
Katja Lutz c9328257db feat: move corporate design section to design accordion item 2 years ago
Katja Lutz 12c9ffb935 feat: change Select input-group size from small to normal 2 years ago
Katja Lutz 72943cc41d feat: convert Select input-group to label 2 years ago
Katja Lutz 514d06b13c chore: improve defaultPositionType select title 2 years ago
Katja Lutz 058c973e15 refactor: extract defaultPositionType select into new Select component 2 years ago
Katja Lutz 4673ba8019 feat: disable word wrapping for invoice position prices and quantity 2 years ago
Katja Lutz 0b55a50d76 feat: preview fullWidthInvoice setting closer to reality 2 years ago
Katja Lutz d90d0b2f8c chore(locale): change word Pixel to Pixeln in WelcomeModal 2 years ago
Katja Lutz 23b3412379 feat: play trailer video in WelcomeModal 2 years ago
Katja Lutz 0462e70229 refactor: replace own shuffle function with external froebel shuffle 2 years ago
Katja Lutz b5530130ef chore(deps): update dependencies 2 years ago
Katja Lutz 994e5d8163 feat: collapse overlay on small devices 2 years ago
Katja Lutz d294c100c6 feat: improve WelcomeModal table of contents layout 2 years ago
Katja Lutz d99c0d6bc2 feat: reduce top margin for WelcomeModal footer on small devices 2 years ago
Katja Lutz b54bb7c1b9 feat: make unsupported devices warning more obvious 2 years ago
Katja Lutz 39a72b6670 fix: in print preview show same page margin independent of fullWidthInvoice 2 years ago
Katja Lutz d04ad556d1 feat: add support for screens with min-width 1024px 2 years ago
Katja Lutz 21017278f2 chore(release): 1.2.0 2 years ago
Katja Lutz cf2a1c4d90 feat: implement custom NumberInput component 2 years ago
Katja Lutz a935e6fe56 feat: support decimals in position quantity input
closes issue #12
2 years ago
Katja Lutz d5a4a739a6 chore: show warning if vatRate is over 100
related issue #11
2 years ago
Katja Lutz 0bb8423b01 feat: support non-numeric characters in line2 street field
closes issue #8
2 years ago
Katja Lutz 6b89e28c5f feat: replace gray with slate bg color for form labels
closes issue #3
2 years ago
Katja Lutz af7511e459 chore(release): 1.1.0 2 years ago
Katja Lutz d20a44990b feat: set maxlength 50 for iban input
closes issue #5
2 years ago
Katja Lutz 95784540c9 feat: implement error handling for QrCode generation
closes issue #4
2 years ago
Katja Lutz 11739dc70c chore(release): 1.0.1 2 years ago
Katja Lutz 82b9ae551a fix: correct typo in label for useCustomAddress input 2 years ago

1
.gitignore vendored

@ -5,6 +5,7 @@ dist
.vercel
.netlify
netlify
/data.json
# dependencies
/node_modules

@ -1,3 +1,5 @@
# Storage
/data.json
# IDEs and editors
/.idea

@ -2,6 +2,58 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [1.3.0](https://git.lufrai.com/rappli/rappli/compare/v1.2.0...v1.3.0) (2022-07-28)
### Features
* add support for screens with min-width 1024px ([d04ad55](https://git.lufrai.com/rappli/rappli/commit/d04ad556d1d30e1760b01a5e9c12beff7f0b4149))
* change Select input-group size from small to normal ([12c9ffb](https://git.lufrai.com/rappli/rappli/commit/12c9ffb93519ff9b8fa785541344dc51e225614d))
* collapse overlay on small devices ([994e5d8](https://git.lufrai.com/rappli/rappli/commit/994e5d81634db5b960d3e80f15af5d0907b6fc6d))
* convert Select input-group to label ([72943cc](https://git.lufrai.com/rappli/rappli/commit/72943cc41d5650db987f058c520a8cc410c0ee15))
* disable word wrapping for invoice position prices and quantity ([4673ba8](https://git.lufrai.com/rappli/rappli/commit/4673ba80194a7934a9fecb85642c31f2986af54a))
* implement addressLayout setting and optimize address layouts for print ([24e82ac](https://git.lufrai.com/rappli/rappli/commit/24e82ace965c2a8c8946f2ce5fc4662d55b98b43)), closes [#14](https://git.lufrai.com/rappli/rappli/issues/14)
* implement like button ([6c80163](https://git.lufrai.com/rappli/rappli/commit/6c801637f6a3131ec10892662c9269a1130714c8)), closes [#18](https://git.lufrai.com/rappli/rappli/issues/18)
* implement logo delete button ([2ffdc40](https://git.lufrai.com/rappli/rappli/commit/2ffdc401f1c432871d7229ac84df0ad238a18585))
* improve WelcomeModal table of contents layout ([d294c10](https://git.lufrai.com/rappli/rappli/commit/d294c100c6d8d430aa12ef05d3880950269fa951))
* make unsupported devices warning more obvious ([b54bb7c](https://git.lufrai.com/rappli/rappli/commit/b54bb7c1b912e2096f93ce03d70c5912c8023dce))
* move corporate design section to design accordion item ([c932825](https://git.lufrai.com/rappli/rappli/commit/c9328257dbd716b01249a4c362a39668c6236c08))
* play trailer video in WelcomeModal ([23b3412](https://git.lufrai.com/rappli/rappli/commit/23b3412379340db9dd8f9b5acfd32ee3afa557d3))
* preview fullWidthInvoice setting closer to reality ([0b55a50](https://git.lufrai.com/rappli/rappli/commit/0b55a50d763bd540f8062688e837cea3b2616665))
* reduce top margin for WelcomeModal footer on small devices ([d99c0d6](https://git.lufrai.com/rappli/rappli/commit/d99c0d6bc28d3c3c63fa23fdd7f836ae277b126c))
* reset lastSaved time after document load ([f4dd2cd](https://git.lufrai.com/rappli/rappli/commit/f4dd2cdb7f87be4c20167268171947673224fb80))
### Bug Fixes
* check for proper error message to silent common typer-js resume bug ([be3d188](https://git.lufrai.com/rappli/rappli/commit/be3d1888b361c8a182ccfaedf10757cea1b30a49))
* in print preview show same page margin independent of fullWidthInvoice ([39a72b6](https://git.lufrai.com/rappli/rappli/commit/39a72b6670b31ecf3c2dee255d087765e931a604))
## [1.2.0](https://git.lufrai.com/rappli/rappli/compare/v1.1.0...v1.2.0) (2022-07-13)
### Features
* implement custom NumberInput component ([cf2a1c4](https://git.lufrai.com/rappli/rappli/commit/cf2a1c4d9040cd4d3a3a317c8bca14c032f5167e))
* replace gray with slate bg color for form labels ([6b89e28](https://git.lufrai.com/rappli/rappli/commit/6b89e28c5f98139a5deee5b4c1786c4d5c1935d8)), closes [#3](https://git.lufrai.com/rappli/rappli/issues/3)
* support decimals in position quantity input ([a935e6f](https://git.lufrai.com/rappli/rappli/commit/a935e6fe563ca9ada14c9dd0ff28551a5e1f69aa)), closes [#12](https://git.lufrai.com/rappli/rappli/issues/12)
* support non-numeric characters in line2 street field ([0bb8423](https://git.lufrai.com/rappli/rappli/commit/0bb8423b01a26d3f96ae5869483611d086fb2606)), closes [#8](https://git.lufrai.com/rappli/rappli/issues/8)
## [1.1.0](https://git.lufrai.com/rappli/rappli/compare/v1.0.1...v1.1.0) (2022-07-07)
### Features
* implement error handling for QrCode generation ([9578454](https://git.lufrai.com/rappli/rappli/commit/95784540c9d447e0d35e82dbfea0d5034fd5a543)), closes [#4](https://git.lufrai.com/rappli/rappli/issues/4)
* set maxlength 50 for iban input ([d20a449](https://git.lufrai.com/rappli/rappli/commit/d20a44990bcdf5ca23bc88959504efa24ded1f7b)), closes [#5](https://git.lufrai.com/rappli/rappli/issues/5)
### [1.0.1](https://git.lufrai.com/rappli/rappli/compare/v1.0.0...v1.0.1) (2022-07-04)
### Bug Fixes
* correct typo in label for useCustomAddress input ([82b9ae5](https://git.lufrai.com/rappli/rappli/commit/82b9ae551aa5432f2af9e62e82960561163abc01))
## [1.0.0](https://git.lufrai.com/rappli/rappli/compare/v0.4.0...v1.0.0) (2022-07-01)

259
package-lock.json generated

@ -1,41 +1,41 @@
{
"name": "rappli",
"version": "1.0.0",
"version": "1.3.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "rappli",
"version": "1.0.0",
"version": "1.3.0",
"license": "MIT",
"dependencies": {
"solid-start": "v0.1.0-alpha.89",
"solid-start-node": "next",
"unplugin-icons": "^0.14.6",
"vite": "^2.9.13"
"unplugin-icons": "^0.14.7",
"vite": "^2.9.14"
},
"bin": {
"rappli": "bin/rappli.js"
},
"devDependencies": {
"@formkit/auto-animate": "^1.0.0-beta.1",
"@iconify/json": "^2.1.69",
"@tailwindcss/typography": "^0.5.2",
"@types/big.js": "^6.1.4",
"@iconify/json": "^2.1.81",
"@tailwindcss/typography": "^0.5.4",
"@types/big.js": "^6.1.5",
"@types/qrcode": "^1.4.2",
"@types/sortablejs": "^1.13.0",
"autoprefixer": "^10.4.2",
"autosize": "^5.0.1",
"big.js": "^6.2.0",
"daisyui": "^2.17.0",
"date-fns": "^2.28.0",
"froebel": "^0.17.0",
"big.js": "^6.2.1",
"daisyui": "^2.20.0",
"date-fns": "^2.29.1",
"froebel": "^0.18.0",
"myzod": "^1.8.7",
"nanoid": "^4.0.0",
"node-iso11649": "^2.1.2",
"postcss": "^8.4.14",
"prettier": "^2.7.1",
"qrcode": "^1.5.0",
"qrcode": "^1.5.1",
"rehype-stringify": "^9.0.3",
"remark": "^14.0.2",
"remark-breaks": "^3.0.2",
@ -44,13 +44,14 @@
"remark-rehype": "^10.1.0",
"shareon": "^2.0.0",
"solid-app-router": "^0.4.1",
"solid-js": "^1.4.5",
"solid-confetti-explosion": "^1.0.3",
"solid-js": "^1.4.8",
"solid-meta": "^0.27.5",
"sortablejs": "^1.15.0",
"standard-version": "^9.5.0",
"tailwindcss": "^3.1.4",
"tailwindcss": "^3.1.6",
"typer-js": "^5.5.3",
"typescript": "^4.6.2",
"typescript": "^4.7.4",
"unified": "^10.1.2"
},
"engines": {
@ -1648,9 +1649,9 @@
}
},
"node_modules/@iconify/json": {
"version": "2.1.69",
"resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.1.69.tgz",
"integrity": "sha512-IJ7InhhWNXfg9apEyDTlGK1Coh5zvSpGStnoOJf36m4Cstqd45qfbObgOevxtUW7zknHlOgMWtw/a9MUNVs1zw==",
"version": "2.1.81",
"resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.1.81.tgz",
"integrity": "sha512-VF2iPSwKJ5WnQFQjzik9s0bJiAa/qhyQIJuvonG2+ZtUK8NVK7v0UmvSNvZQv8Nt//df6p3tZFZTTD2eRRVi5Q==",
"dev": true,
"dependencies": {
"@iconify/types": "*",
@ -1826,9 +1827,9 @@
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
},
"node_modules/@tailwindcss/typography": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.2.tgz",
"integrity": "sha512-coq8DBABRPFcVhVIk6IbKyyHUt7YTEC/C992tatFB+yEx5WGBQrCgsSFjxHUr8AWXphWckadVJbominEduYBqw==",
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.4.tgz",
"integrity": "sha512-QEdg40EmGvE7kKoDei8zr5sf4D1pIayHj4R31bH3lX8x2BtTiR+jNejYPOkhbmy3DXgkMF9jC8xqNiGFAuL9Sg==",
"dev": true,
"dependencies": {
"lodash.castarray": "^4.4.0",
@ -1836,13 +1837,13 @@
"lodash.merge": "^4.6.2"
},
"peerDependencies": {
"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || insiders"
"tailwindcss": ">=3.0.0 || insiders"
}
},
"node_modules/@types/big.js": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-6.1.4.tgz",
"integrity": "sha512-yBEfFBLpvnIS9MLcKG4XIpBhMRjDWEf4cSJ/uR5cPq2JrYB+yhYMPK8cF17hGfWmsWL7LuzJF/N4APRtmcg4sw==",
"version": "6.1.5",
"resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-6.1.5.tgz",
"integrity": "sha512-UiWyJ6TLWoHeHZ8VUyngzCOwJDVxTsPnqfAMR/85X93rkRk5A4T2U42BCx0wCmZdtMHGHN/utJ8ft5xWu0V1bA==",
"dev": true
},
"node_modules/@types/debug": {
@ -2180,9 +2181,9 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/big.js": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.0.tgz",
"integrity": "sha512-paIKvJiAaOYdLt6MfnvxkDo64lTOV257XYJyX3oJnJQocIclUn+48k6ZerH/c5FxWE6DGJu1TKDYis7tqHg9kg==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz",
"integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==",
"dev": true,
"engines": {
"node": "*"
@ -2926,16 +2927,23 @@
"node": ">=4"
}
},
"node_modules/csstype": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==",
"dev": true,
"peer": true
},
"node_modules/daisyui": {
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.17.0.tgz",
"integrity": "sha512-U8eA8IvwH0JSi72WbRZdmJcYZek3ERMPFPAVFhnYc6dGnobeIHLGBz8J4q012I9YVDUqXFrWz13rpn+SBdn7qQ==",
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.20.0.tgz",
"integrity": "sha512-97xFBWQOXV/JCVRrGI5xranElKMmXIajDxojTQ1qoYwcWlkfFE7hY4D/NyHVIzlQb+B4xbiXhVPJM7EleRAY8g==",
"dev": true,
"dependencies": {
"color": "^4.2",
"css-selector-tokenizer": "^0.8.0",
"postcss-js": "^4.0.0",
"tailwindcss": "^3.0"
"tailwindcss": "^3"
},
"peerDependencies": {
"autoprefixer": "^10.0.2",
@ -2952,9 +2960,9 @@
}
},
"node_modules/date-fns": {
"version": "2.28.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz",
"integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==",
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.1.tgz",
"integrity": "sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==",
"dev": true,
"engines": {
"node": ">=0.11"
@ -3778,9 +3786,9 @@
}
},
"node_modules/froebel": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/froebel/-/froebel-0.17.0.tgz",
"integrity": "sha512-reZdfnUIXBF6a1s6mcwx+DctPRZYGmNcU5kUAq47yrQ4rvpSKw/yN4eCIs4uEFLHUpT7bSBnqd60jC2jN7fbGg==",
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/froebel/-/froebel-0.18.0.tgz",
"integrity": "sha512-dPkcmnYFA58qLY29MExdUg6/DopBfSeltd66oR9MosezkkXOdjHt0qvNPQbsaAdavJkzqEusiWxOa5TvFjMo5g==",
"dev": true
},
"node_modules/fs.realpath": {
@ -4073,6 +4081,16 @@
"node": ">=4"
}
},
"node_modules/goober": {
"version": "2.1.10",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.10.tgz",
"integrity": "sha512-7PpuQMH10jaTWm33sQgBQvz45pHR8N4l3Cu3WMGEWmHShAcTuuP7I+5/DwKo39fwti5A80WAjvqgz6SSlgWmGA==",
"dev": true,
"peer": true,
"peerDependencies": {
"csstype": "^3.0.10"
}
},
"node_modules/graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
@ -6338,9 +6356,9 @@
}
},
"node_modules/qrcode": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.0.tgz",
"integrity": "sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ==",
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz",
"integrity": "sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==",
"dev": true,
"dependencies": {
"dijkstrajs": "^1.0.1",
@ -6932,10 +6950,20 @@
"solid-js": "^1.3.5"
}
},
"node_modules/solid-confetti-explosion": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/solid-confetti-explosion/-/solid-confetti-explosion-1.0.3.tgz",
"integrity": "sha512-rAxyxcyhkb7ZCO9fU6YAbH65YH/4+4sCAyaGasd4WzX7XZEpV4bO+VYGYNDV78e/RDwB/8b+PWH25fqwI/igHw==",
"dev": true,
"peerDependencies": {
"solid-js": "^1.4.5",
"solid-styled-components": "^0.28.4"
}
},
"node_modules/solid-js": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.4.5.tgz",
"integrity": "sha512-32NGpuabEJDTeQ7fjaTR2TLC7R/X5hbqhYdEQ1e+GcIK8r8+/V0Nv17eZQii5Z/97/mtdt8yi63chzg73qnz/A=="
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.4.8.tgz",
"integrity": "sha512-XErZdnnYYXF7OwGSUAPcua2y5/ELB/c53zFCpWiEGqxTNoH1iQghzI8EsHJXk06sNn+Z/TGhb8bPDNNGSgimag=="
},
"node_modules/solid-meta": {
"version": "0.27.5",
@ -7020,6 +7048,20 @@
"vite": "*"
}
},
"node_modules/solid-styled-components": {
"version": "0.28.4",
"resolved": "https://registry.npmjs.org/solid-styled-components/-/solid-styled-components-0.28.4.tgz",
"integrity": "sha512-SGbXv5tLIs1qErr3x7M+HWE4lu+37C4myV8gbce7WnZumjBmM5sifKv/NulVeSf3nMRa3uwkAM14q7QmLGC2gQ==",
"dev": true,
"peer": true,
"dependencies": {
"csstype": "^3.1.0",
"goober": "^2.1.10"
},
"peerDependencies": {
"solid-js": "^1.4.4"
}
},
"node_modules/sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
@ -7368,9 +7410,9 @@
}
},
"node_modules/tailwindcss": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.4.tgz",
"integrity": "sha512-NrxbFV4tYsga/hpWbRyUfIaBrNMXDxx5BsHgBS4v5tlyjf+sDsgBg5m9OxjrXIqAS/uR9kicxLKP+bEHI7BSeQ==",
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.6.tgz",
"integrity": "sha512-7skAOY56erZAFQssT1xkpk+kWt2NrO45kORlxFPXUt3CiGsVPhH1smuH5XoDH6sGPXLyBv+zgCKA2HWBsgCytg==",
"dev": true,
"dependencies": {
"arg": "^5.0.2",
@ -7394,7 +7436,7 @@
"postcss-selector-parser": "^6.0.10",
"postcss-value-parser": "^4.2.0",
"quick-lru": "^5.1.1",
"resolve": "^1.22.0"
"resolve": "^1.22.1"
},
"bin": {
"tailwind": "lib/cli.js",
@ -7751,9 +7793,9 @@
}
},
"node_modules/unplugin-icons": {
"version": "0.14.6",
"resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-0.14.6.tgz",
"integrity": "sha512-8sxDiL4l+TV4zufZfrskgHZZSDFoGOCBgYsefRMM4inQ3Z6KhgMSuNyew7U7D/xG//rwxgD7bN+Dv+YAZEEfEw==",
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-0.14.7.tgz",
"integrity": "sha512-TrNnEdpaXMdiG5BsCgvU6cv/gSLYvIk1f8wGCGZmOo4wmi3nqYBuqIEuiXhmmyXdDZuRRpCaOzCnCYYZ5H7U8g==",
"dependencies": {
"@antfu/install-pkg": "^0.1.0",
"@antfu/utils": "^0.5.2",
@ -7879,9 +7921,9 @@
}
},
"node_modules/vite": {
"version": "2.9.13",
"resolved": "https://registry.npmjs.org/vite/-/vite-2.9.13.tgz",
"integrity": "sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==",
"version": "2.9.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-2.9.14.tgz",
"integrity": "sha512-P/UCjSpSMcE54r4mPak55hWAZPlyfS369svib/gpmz8/01L822lMPOJ/RYW6tLCe1RPvMvOsJ17erf55bKp4Hw==",
"dependencies": {
"esbuild": "^0.14.27",
"postcss": "^8.4.13",
@ -9260,9 +9302,9 @@
"dev": true
},
"@iconify/json": {
"version": "2.1.69",
"resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.1.69.tgz",
"integrity": "sha512-IJ7InhhWNXfg9apEyDTlGK1Coh5zvSpGStnoOJf36m4Cstqd45qfbObgOevxtUW7zknHlOgMWtw/a9MUNVs1zw==",
"version": "2.1.81",
"resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.1.81.tgz",
"integrity": "sha512-VF2iPSwKJ5WnQFQjzik9s0bJiAa/qhyQIJuvonG2+ZtUK8NVK7v0UmvSNvZQv8Nt//df6p3tZFZTTD2eRRVi5Q==",
"dev": true,
"requires": {
"@iconify/types": "*",
@ -9401,9 +9443,9 @@
}
},
"@tailwindcss/typography": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.2.tgz",
"integrity": "sha512-coq8DBABRPFcVhVIk6IbKyyHUt7YTEC/C992tatFB+yEx5WGBQrCgsSFjxHUr8AWXphWckadVJbominEduYBqw==",
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.4.tgz",
"integrity": "sha512-QEdg40EmGvE7kKoDei8zr5sf4D1pIayHj4R31bH3lX8x2BtTiR+jNejYPOkhbmy3DXgkMF9jC8xqNiGFAuL9Sg==",
"dev": true,
"requires": {
"lodash.castarray": "^4.4.0",
@ -9412,9 +9454,9 @@
}
},
"@types/big.js": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-6.1.4.tgz",
"integrity": "sha512-yBEfFBLpvnIS9MLcKG4XIpBhMRjDWEf4cSJ/uR5cPq2JrYB+yhYMPK8cF17hGfWmsWL7LuzJF/N4APRtmcg4sw==",
"version": "6.1.5",
"resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-6.1.5.tgz",
"integrity": "sha512-UiWyJ6TLWoHeHZ8VUyngzCOwJDVxTsPnqfAMR/85X93rkRk5A4T2U42BCx0wCmZdtMHGHN/utJ8ft5xWu0V1bA==",
"dev": true
},
"@types/debug": {
@ -9697,9 +9739,9 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"big.js": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.0.tgz",
"integrity": "sha512-paIKvJiAaOYdLt6MfnvxkDo64lTOV257XYJyX3oJnJQocIclUn+48k6ZerH/c5FxWE6DGJu1TKDYis7tqHg9kg==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz",
"integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==",
"dev": true
},
"binary-extensions": {
@ -10254,16 +10296,23 @@
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true
},
"csstype": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==",
"dev": true,
"peer": true
},
"daisyui": {
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.17.0.tgz",
"integrity": "sha512-U8eA8IvwH0JSi72WbRZdmJcYZek3ERMPFPAVFhnYc6dGnobeIHLGBz8J4q012I9YVDUqXFrWz13rpn+SBdn7qQ==",
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.20.0.tgz",
"integrity": "sha512-97xFBWQOXV/JCVRrGI5xranElKMmXIajDxojTQ1qoYwcWlkfFE7hY4D/NyHVIzlQb+B4xbiXhVPJM7EleRAY8g==",
"dev": true,
"requires": {
"color": "^4.2",
"css-selector-tokenizer": "^0.8.0",
"postcss-js": "^4.0.0",
"tailwindcss": "^3.0"
"tailwindcss": "^3"
}
},
"dargs": {
@ -10273,9 +10322,9 @@
"dev": true
},
"date-fns": {
"version": "2.28.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz",
"integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==",
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.1.tgz",
"integrity": "sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==",
"dev": true
},
"dateformat": {
@ -10792,9 +10841,9 @@
"dev": true
},
"froebel": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/froebel/-/froebel-0.17.0.tgz",
"integrity": "sha512-reZdfnUIXBF6a1s6mcwx+DctPRZYGmNcU5kUAq47yrQ4rvpSKw/yN4eCIs4uEFLHUpT7bSBnqd60jC2jN7fbGg==",
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/froebel/-/froebel-0.18.0.tgz",
"integrity": "sha512-dPkcmnYFA58qLY29MExdUg6/DopBfSeltd66oR9MosezkkXOdjHt0qvNPQbsaAdavJkzqEusiWxOa5TvFjMo5g==",
"dev": true
},
"fs.realpath": {
@ -11013,6 +11062,14 @@
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
},
"goober": {
"version": "2.1.10",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.10.tgz",
"integrity": "sha512-7PpuQMH10jaTWm33sQgBQvz45pHR8N4l3Cu3WMGEWmHShAcTuuP7I+5/DwKo39fwti5A80WAjvqgz6SSlgWmGA==",
"dev": true,
"peer": true,
"requires": {}
},
"graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
@ -12544,9 +12601,9 @@
"dev": true
},
"qrcode": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.0.tgz",
"integrity": "sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ==",
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz",
"integrity": "sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==",
"dev": true,
"requires": {
"dijkstrajs": "^1.0.1",
@ -12975,10 +13032,17 @@
"integrity": "sha512-RKHyFQ+J5lXyE/SoyJVHgTBeBck2etYVJn1/9F7ehlzyD2pIOMqLpNXD1GfWQljHqNdXZBSyE+xB/Cck5l9Q/g==",
"requires": {}
},
"solid-confetti-explosion": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/solid-confetti-explosion/-/solid-confetti-explosion-1.0.3.tgz",
"integrity": "sha512-rAxyxcyhkb7ZCO9fU6YAbH65YH/4+4sCAyaGasd4WzX7XZEpV4bO+VYGYNDV78e/RDwB/8b+PWH25fqwI/igHw==",
"dev": true,
"requires": {}
},
"solid-js": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.4.5.tgz",
"integrity": "sha512-32NGpuabEJDTeQ7fjaTR2TLC7R/X5hbqhYdEQ1e+GcIK8r8+/V0Nv17eZQii5Z/97/mtdt8yi63chzg73qnz/A=="
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.4.8.tgz",
"integrity": "sha512-XErZdnnYYXF7OwGSUAPcua2y5/ELB/c53zFCpWiEGqxTNoH1iQghzI8EsHJXk06sNn+Z/TGhb8bPDNNGSgimag=="
},
"solid-meta": {
"version": "0.27.5",
@ -13041,6 +13105,17 @@
"sirv": "^1.0.12"
}
},
"solid-styled-components": {
"version": "0.28.4",
"resolved": "https://registry.npmjs.org/solid-styled-components/-/solid-styled-components-0.28.4.tgz",
"integrity": "sha512-SGbXv5tLIs1qErr3x7M+HWE4lu+37C4myV8gbce7WnZumjBmM5sifKv/NulVeSf3nMRa3uwkAM14q7QmLGC2gQ==",
"dev": true,
"peer": true,
"requires": {
"csstype": "^3.1.0",
"goober": "^2.1.10"
}
},
"sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
@ -13302,9 +13377,9 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
},
"tailwindcss": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.4.tgz",
"integrity": "sha512-NrxbFV4tYsga/hpWbRyUfIaBrNMXDxx5BsHgBS4v5tlyjf+sDsgBg5m9OxjrXIqAS/uR9kicxLKP+bEHI7BSeQ==",
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.6.tgz",
"integrity": "sha512-7skAOY56erZAFQssT1xkpk+kWt2NrO45kORlxFPXUt3CiGsVPhH1smuH5XoDH6sGPXLyBv+zgCKA2HWBsgCytg==",
"dev": true,
"requires": {
"arg": "^5.0.2",
@ -13328,7 +13403,7 @@
"postcss-selector-parser": "^6.0.10",
"postcss-value-parser": "^4.2.0",
"quick-lru": "^5.1.1",
"resolve": "^1.22.0"
"resolve": "^1.22.1"
},
"dependencies": {
"glob-parent": {
@ -13570,9 +13645,9 @@
}
},
"unplugin-icons": {
"version": "0.14.6",
"resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-0.14.6.tgz",
"integrity": "sha512-8sxDiL4l+TV4zufZfrskgHZZSDFoGOCBgYsefRMM4inQ3Z6KhgMSuNyew7U7D/xG//rwxgD7bN+Dv+YAZEEfEw==",
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-0.14.7.tgz",
"integrity": "sha512-TrNnEdpaXMdiG5BsCgvU6cv/gSLYvIk1f8wGCGZmOo4wmi3nqYBuqIEuiXhmmyXdDZuRRpCaOzCnCYYZ5H7U8g==",
"requires": {
"@antfu/install-pkg": "^0.1.0",
"@antfu/utils": "^0.5.2",
@ -13644,9 +13719,9 @@
}
},
"vite": {
"version": "2.9.13",
"resolved": "https://registry.npmjs.org/vite/-/vite-2.9.13.tgz",
"integrity": "sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==",
"version": "2.9.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-2.9.14.tgz",
"integrity": "sha512-P/UCjSpSMcE54r4mPak55hWAZPlyfS369svib/gpmz8/01L822lMPOJ/RYW6tLCe1RPvMvOsJ17erf55bKp4Hw==",
"requires": {
"esbuild": "^0.14.27",
"fsevents": "~2.3.2",

@ -1,6 +1,6 @@
{
"name": "rappli",
"version": "1.0.0",
"version": "1.3.0",
"bin": "./bin/rappli.js",
"scripts": {
"dev": "solid-start dev",
@ -21,23 +21,23 @@
"type": "module",
"devDependencies": {
"@formkit/auto-animate": "^1.0.0-beta.1",
"@iconify/json": "^2.1.69",
"@tailwindcss/typography": "^0.5.2",
"@types/big.js": "^6.1.4",
"@iconify/json": "^2.1.81",
"@tailwindcss/typography": "^0.5.4",
"@types/big.js": "^6.1.5",
"@types/qrcode": "^1.4.2",
"@types/sortablejs": "^1.13.0",
"autoprefixer": "^10.4.2",
"autosize": "^5.0.1",
"big.js": "^6.2.0",
"daisyui": "^2.17.0",
"date-fns": "^2.28.0",
"froebel": "^0.17.0",
"big.js": "^6.2.1",
"daisyui": "^2.20.0",
"date-fns": "^2.29.1",
"froebel": "^0.18.0",
"myzod": "^1.8.7",
"nanoid": "^4.0.0",
"node-iso11649": "^2.1.2",
"postcss": "^8.4.14",
"prettier": "^2.7.1",
"qrcode": "^1.5.0",
"qrcode": "^1.5.1",
"rehype-stringify": "^9.0.3",
"remark": "^14.0.2",
"remark-breaks": "^3.0.2",
@ -46,13 +46,14 @@
"remark-rehype": "^10.1.0",
"shareon": "^2.0.0",
"solid-app-router": "^0.4.1",
"solid-js": "^1.4.5",
"solid-confetti-explosion": "^1.0.3",
"solid-js": "^1.4.8",
"solid-meta": "^0.27.5",
"sortablejs": "^1.15.0",
"standard-version": "^9.5.0",
"tailwindcss": "^3.1.4",
"tailwindcss": "^3.1.6",
"typer-js": "^5.5.3",
"typescript": "^4.6.2",
"typescript": "^4.7.4",
"unified": "^10.1.2"
},
"engines": {
@ -61,8 +62,8 @@
"dependencies": {
"solid-start": "v0.1.0-alpha.89",
"solid-start-node": "next",
"unplugin-icons": "^0.14.6",
"vite": "^2.9.13"
"unplugin-icons": "^0.14.7",
"vite": "^2.9.14"
},
"standard-version": {
"scripts": {

Binary file not shown.

@ -1,26 +1,31 @@
import { formatISO9075, fromUnixTime, getUnixTime } from "date-fns";
import {
Component,
JSX,
Show,
mergeProps,
splitProps,
FlowComponent,
createSignal,
createEffect,
For,
} from "solid-js";
import { validateInput } from "~/hooks/validation";
import AsteriskIcon from "~icons/ph/asterisk-bold";
import MaximizeIcon from "~icons/carbon/maximize";
import MinimizeIcon from "~icons/carbon/minimize";
import autosize from "autosize";
import type { JSX } from "solid-js";
import {
createNativeInputValue,
createOptionalNumberInputHandler,
} from "~/util";
export const TextInput: Component<
{
label: string;
placeholder?: string;
labelMinWidth?: string;
suffix?: string;
suffix?: string | JSX.Element;
size?: string;
vertical?: boolean;
} & JSX.InputHTMLAttributes<HTMLInputElement>
@ -71,6 +76,7 @@ export const TextInput: Component<
"gap-1": true,
"h-8": props.vertical,
"font-bold": rest.required,
"bg-slate-200/70": vState().valid,
"bg-red-100": !vState().valid,
}}
>
@ -89,13 +95,13 @@ export const TextInput: Component<
[props.class || ""]: true,
}}
type="text"
lang={rest.type === "number" ? "en" : undefined}
placeholder={props.placeholder}
{...rest}
/>
<Show when={props.suffix}>
<span
classList={{
"bg-slate-200/70": vState().valid,
"bg-red-100": !vState().valid,
}}
>
@ -154,7 +160,7 @@ export const TextArea: Component<
</Show>
</button>
<label class="input-group input-group-vertical">
<span class="h-8 flex gap-2 justify-between pr-14">
<span class="h-8 bg-slate-200/70 flex gap-2 justify-between pr-14">
{props.label}
{props.labelSuffixJsx}
</span>
@ -216,3 +222,79 @@ export const UnixDateInput: Component<
/>
);
};
export const NumberInput: Component<
{ value?: number; onInput: (v: number | undefined) => void } & Omit<
Parameters<typeof TextInput>[0],
"onInput"
>
> = (p) => {
let el: HTMLInputElement = undefined!;
const [props, rest] = splitProps(p, ["value", "onInput"]);
const value = createNativeInputValue(
() => el,
() => props.value
);
return (
<TextInput
ref={el}
value={value()}
maxLength={9}
onInput={createOptionalNumberInputHandler(props.onInput)}
{...rest}
/>
);
};
// TODO: Move input-group into separate component
export const Select: Component<
{
value: string | number;
options: [string | number, string][];
label: string;
labelMinWidth?: string;
onChange: (v: any) => void;
} & JSX.InputHTMLAttributes<HTMLSelectElement>
> = (p) => {
p = mergeProps(
{
labelMinWidth: "95px",
},
p
);
const [props, rest] = splitProps(p, [
"value",
"options",
"label",
"labelMinWidth",
"onChange",
]);
return (
<div class="shrink form-control">
<label class="input-group">
<span
class="bg-slate-200/70"
style={{ "min-width": props.labelMinWidth }}
>
{props.label}
</span>
<select
class="flex-1 select select-sm select-bordered"
onChange={(e) => props.onChange(e.currentTarget.value)}
{...rest}
>
<For each={props.options}>
{([type, label]) => (
<option selected={type === props.value} value={type}>
{label}
</option>
)}
</For>
</select>
</label>
</div>
);
};

@ -20,7 +20,7 @@ const Modal: FlowComponent<{ open: boolean }> = (props) => {
"!visible": isVisible(),
}}
>
<div class="modal-box relative py-16 w-11/12 lg:w-2/3 xxl:w-1/2 lg:p-16 max-w-none overflow-hidden">
<div class="modal-box relative py-16 w-11/12 lg:w-3/4 xl:w-2/3 xxl:w-1/2 lg:p-16 max-w-none overflow-hidden">
{props.children}
</div>
</div>

@ -48,7 +48,7 @@ const Page: FlowComponent = (props) => {
});
return (
<div class="flex-1 flex flex-col justify-start print:block overflow-y-hidden overflow-x-hidden xxl:overflow-y-auto items-center xl:max-w-[none] max-h-screen xl:max-h-[none] print:max-h-[none] min-h-screen print:min-h-0 p-5 pt-3 print:p-0">
<div class="flex-1 flex flex-col justify-start print:block overflow-y-hidden overflow-x-hidden xxl:overflow-y-auto items-center lg:max-w-[none] max-h-screen lg:max-h-[none] print:max-h-[none] min-h-screen print:min-h-0 p-5 pt-3 print:p-0">
<div
aria-disabled="true"
class="print:hidden text-xs text-black text-opacity-50 uppercase mb-2"
@ -71,7 +71,7 @@ const Page: FlowComponent = (props) => {
{lastSavedWords()}
</span>
</div>
<div class="w-[1200px] shrink-0 scale-[.5] lg:scale-90 xl:scale-100 origin-top print:scale-100 shadow-md print:shadow-none print:w-full bg-white p-5 print:p-0">
<div class="w-[900px] lg:w-[1000px] xl:w-[1100px] xxl:w-[1200px] print:w-full shrink-0 scale-75 md:scale-90 lg:scale-100 origin-top print:scale-100 shadow-md print:shadow-none bg-white py-5 print:p-0">
{props.children}
</div>
</div>

@ -146,7 +146,7 @@ const Positions: Component<{
</td>
<td
classList={{
"align-top text-center": true,
"align-top text-center !whitespace-nowrap": true,
"border-b-0 pb-0": hasTwoRows(),
}}
>
@ -154,7 +154,7 @@ const Positions: Component<{
</td>
<td
classList={{
"align-top text-right": true,
"align-top text-right !whitespace-nowrap": true,
"border-b-0 pb-0": hasTwoRows(),
}}
>
@ -167,7 +167,7 @@ const Positions: Component<{
</td>
<td
classList={{
"align-top text-right ": true,
"align-top text-right !whitespace-nowrap": true,
"border-b-0 pb-0": hasTwoRows(),
"line-through": position.fixedDiscountPrice != null,
}}
@ -185,7 +185,7 @@ const Positions: Component<{
/>
</Show>
</td>
<td class="align-top pt-1 text-right">
<td class="align-top pt-1 text-right !whitespace-nowrap">
<Show when={position.fixedDiscountPrice != null}>
{formatAmount(position.fixedDiscountPrice!)} CHF
</Show>
@ -202,7 +202,7 @@ const Positions: Component<{
<td class="align-bottom">Summe</td>
<td></td>
<td></td>
<td class="text-right align-bottom">
<td class="text-right align-bottom !whitespace-nowrap">
{formatAmount(props.invoiceData.amountBeforeTax)} CHF
</td>
</tr>
@ -214,7 +214,7 @@ const Positions: Component<{
</td>
<td></td>
<td></td>
<td class="text-right">
<td class="text-right !whitespace-nowrap">
{formatAmount(props.invoiceData.tax)} CHF
</td>
</tr>
@ -224,7 +224,7 @@ const Positions: Component<{
<td class="align-bottom">Gesamtbetrag</td>
<td></td>
<td></td>
<td class="align-bottom text-right">
<td class="align-bottom text-right !whitespace-nowrap">
{formatAmount(props.invoiceData.amount)} CHF
</td>
</tr>

@ -2,10 +2,13 @@ import {
Component,
createEffect,
createResource,
createSignal,
JSX,
Show,
splitProps,
} from "solid-js";
import qrcode from "qrcode";
import WarningIcon from "~icons/carbon/warning-alt-filled";
const QrCode: Component<
{
@ -21,15 +24,26 @@ const QrCode: Component<
]);
let ref: HTMLDivElement = undefined!;
const [qrError, setQrError] = createSignal<string | undefined>();
const [svg] = createResource(
() => props.value,
(value) => {
return qrcode.toString(value, {
type: "svg",
margin: props.margin,
errorCorrectionLevel: props.errorCorrectionLevel as any,
});
async (value) => {
let svg;
try {
svg = await qrcode.toString(value, {
type: "svg",
margin: props.margin,
errorCorrectionLevel: props.errorCorrectionLevel as any,
});
setQrError();
} catch (err) {
console.error(err);
setQrError((err as Error).message);
}
return svg;
}
);
@ -40,7 +54,17 @@ const QrCode: Component<
});
});
return <div ref={ref} {...rest}></div>;
return (
<>
<Show when={qrError()}>
<div class="absolute h-full p-3 gap-2 rounded-sm flex items-start bg-error/80 backdrop-blur-sm ring-2 ring-error ring-offset-2 border border-error text-error-content overflow-y-auto">
<WarningIcon width="2em" height="2em" class="flex-shrink-0" /> Fehler:{" "}
{qrError()}
</div>
</Show>
<div ref={ref} {...rest}></div>
</>
);
};
export default QrCode;

File diff suppressed because it is too large Load Diff

@ -21,9 +21,13 @@ import AddIcon from "~icons/carbon/add-filled";
import DeleteIcon from "~icons/carbon/trash-can";
import DragVerticalIcon from "~icons/carbon/drag-vertical";
import PositionSettingsIcon from "~icons/carbon/settings-adjust";
import { Checkbox, TextArea, TextInput } from "../Form";
import { Checkbox, NumberInput, TextArea, TextInput } from "../Form";
import { MarkdownHelpLabel } from "../Markdown";
import { createOptionalNumberInputHandler } from "~/util";
import {
createOptionalNumberInputHandler,
createNativeInputValue,
resetInput,
} from "~/util";
export const PositionsSettings: Component = () => {
const [state, setState] = useContext(StoreContext)!;
@ -125,6 +129,12 @@ export const PositionsSettings: Component = () => {
);
};
let quantityInputEl: HTMLInputElement = undefined!;
const quantityValue = createNativeInputValue(
() => quantityInputEl,
() => position.quantity
);
return (
<div class="indicator w-full">
<div class="indicator-item indicator-middle indicator-end flex items-center">
@ -243,24 +253,24 @@ export const PositionsSettings: Component = () => {
<Show when={position.type === POSITION_TYPE_QUANTITY}>
<div class="flex-1">
<input
ref={quantityInputEl}
class="w-full input input-bordered input-xs"
value={
position.quantity === 0
? ""
: position.quantity
}
value={quantityValue()}
placeholder="Menge"
min="0"
required
type="number"
onInput={(e) => {
setState(
"positions",
idx(),
"quantity",
parseFloat(e.currentTarget.value) || 0
);
}}
name="Menge"
onInput={createOptionalNumberInputHandler(
(v) => {
v != null &&
setState(
"positions",
idx(),
"quantity",
v
);
}
)}
onBlur={resetInput(0)}
/>
</div>
</Show>
@ -293,7 +303,7 @@ export const PositionsSettings: Component = () => {
</Show>
</div>
</div>
<TextInput
<NumberInput
size="xs"
value={position.itemPrice}
label="Einzelpreis"
@ -302,12 +312,9 @@ export const PositionsSettings: Component = () => {
? state.defaultItemPrice + ""
: undefined
}
step="0.01"
min="0"
type="number"
onInput={createOptionalNumberInputHandler((v) =>
onInput={(v) =>
setState("positions", idx(), "itemPrice", v)
)}
}
/>
<div
use:autoAnimate
@ -348,21 +355,18 @@ export const PositionsSettings: Component = () => {
/>
</div>
<div class="col-span-2">
<TextInput
<NumberInput
label="Aktionspreis"
suffix="CHF"
type="number"
step="0.01"
min="0"
value={position.fixedDiscountPrice}
onInput={createOptionalNumberInputHandler((v) =>
onInput={(v) =>
setState(
"positions",
idx(),
"fixedDiscountPrice",
v
)
)}
}
/>
</div>
<div class="col-span-2">

@ -8,13 +8,22 @@ import {
JSX,
useContext,
splitProps,
createSignal,
Show,
For,
untrack,
createResource,
} from "solid-js";
import { createStore } from "solid-js/store";
import LufraiLogo from "~icons/custom/lufrai-logo";
import AppIcon from "~icons/custom/icon";
import ExternalLinkIcon from "~icons/carbon/launch";
import WarningIcon from "~icons/carbon/warning-alt-filled";
import LaunchIcon from "~icons/carbon/edit";
import DonationIcon from "~icons/carbon/favorite-filled";
import DonationIcon from "~icons/bxs/donate-heart";
import FavoriteIcon from "~icons/carbon/favorite";
import FavoriteHalfIcon from "~icons/carbon/favorite-half";
import FavoriteFilledIcon from "~icons/carbon/favorite-filled";
import WatermarkIcon from "~icons/carbon/bullhorn";
import FreedomIcon from "~icons/noto/butterfly";
import FreeIcon from "~icons/noto/seedling";
@ -22,6 +31,8 @@ import PrivacyIcon from "~icons/noto/princess";
import AgileIcon from "~icons/noto/person-bouncing-ball";
import ResultIcon from "~icons/noto/chequered-flag";
import HugIcon from "~icons/noto/hugging-face";
import VideoIcon from "~icons/carbon/video-filled";
import CloseIcon from "~icons/carbon/close-outline";
import Modal, { ModalCloseButton } from "./Modal";
import { LocalStoreContext } from "~/stores";
import createAccordion from "./Accordion";
@ -33,16 +44,19 @@ import {
getDomain,
getHost,
onClickFocus,
shuffle,
} from "~/util";
import { capitalize } from "froebel";
import { capitalize, clamp, shuffle } from "froebel";
import { markdownHelpUrl } from "./Markdown";
import AgileCalculator from "./AgileCalculator";
import server from "solid-start/server";
import { getLikes, increaseLikes } from "~/server/likes";
export const description =
"Räppli ist eine freie Web App zur Erstellung von Schweizerischen Rechnungen inklusive QR-Code. Erfasse deine Rechnungspositionen und erhalte unmittelbar eine druckbare Rechnung.";
const externalLinkClass = "inline-flex items-center gap-1";
import ConfettiExplosion from "solid-confetti-explosion";
// TODO: after solid-start update >= alpha.95, switch to lazy
// const ConfettiExplosion = lazy(() => import("solid-confetti-explosion"));
const ExternalLink: FlowComponent<
JSX.AnchorHTMLAttributes<HTMLAnchorElement>
@ -64,6 +78,9 @@ const WelcomeModal: Component = (props) => {
const isOpen = createMemo(() => {
return localStateMounted() && localState.showWelcome;
});
const [showTrailer, setShowTrailer] = createSignal(false);
const increaseCount_ = server(increaseLikes);
const [likes] = createResource(server(getLikes));
onMount(function () {
let adjectives = [
@ -124,7 +141,7 @@ const WelcomeModal: Component = (props) => {
// typer-js has some weird logic how it handles halt / resume. Essentially if halt wasn't executed before of resume, resume breaks completely
halted && typerInstance.resume();
} catch (err) {
if ((err as TypeError).message != "u.resume is not a function") {
if (!(err as TypeError).message.endsWith("is not a function")) {
console.dir(err);
}
}
@ -164,10 +181,33 @@ const WelcomeModal: Component = (props) => {
"Rahel Lutz",
]);
thankYouRahelAndFredi.splice(1, 0, " und ");
const [likeCount, setLikeCount] = createSignal(0);
const [confetti, setConfetti] = createStore([false, false, false]);
const confettiDuration = 2000;
createEffect(function () {
if (likeCount() == 0) {
return;
}
untrack(function () {
for (const idx of confetti.keys()) {
if (confetti[idx]) {
continue;
}
setConfetti(idx, true);
setTimeout(
() => setConfetti(idx, false),
(confettiDuration / 100) * 80
);
break;
}
});
});
return (
<Modal open={isOpen()}>
<div class="hidden xl:block">
<div class="hidden lg:block">
<ModalCloseButton onClick={() => setLocalState("showWelcome", false)} />
</div>
<div class="max-h-[60vh] overflow-y-auto px-2">
@ -199,7 +239,37 @@ const WelcomeModal: Component = (props) => {
</div>
</div>
<div class="mt-28 text-base flex flex-wrap text-center gap-7 items-center justify-center">
<Show when={showTrailer()}>
{() => (
<div class="absolute top-0 left-0 h-full w-full flex flex-col justify-center items-center gap-8 bg-black backdrop-blur bg-opacity-90 [@supports(backdrop-filter:blur(0))]:bg-opacity-70 z-10">
<video
controls
autoplay
onended={() => setShowTrailer(false)}
>
<source src="/RaeppliTrailer.mp4" type="video/mp4" />
</video>
<button
class="btn btn-accent btn-xl gap-2"
onClick={() => setShowTrailer(false)}
>
<CloseIcon />
Schliessen
</button>