coyotte508 HF staff commited on
Commit
8a49743
1 Parent(s): de10f77

✨ Upload new photos & products, delete existing products

Browse files
package.json CHANGED
@@ -17,8 +17,10 @@
17
  "@sveltejs/adapter-node": "next",
18
  "@sveltejs/kit": "next",
19
  "@types/bcryptjs": "^2.4.2",
 
20
  "@types/lodash": "^4.14.188",
21
  "@types/marked": "^4.0.7",
 
22
  "@typescript-eslint/eslint-plugin": "^5.27.0",
23
  "@typescript-eslint/parser": "^5.27.0",
24
  "@unocss/preset-icons": "^0.46.3",
@@ -41,11 +43,14 @@
41
  "type": "module",
42
  "dependencies": {
43
  "bcryptjs": "^2.4.3",
 
44
  "date-fns": "^2.29.3",
45
  "form-data": "^4.0.0",
46
  "lodash": "^4.17.21",
47
  "mailgun.js": "^8.0.2",
48
  "marked": "^4.2.2",
49
- "mongodb": "^4.11.0"
 
 
50
  }
51
  }
 
17
  "@sveltejs/adapter-node": "next",
18
  "@sveltejs/kit": "next",
19
  "@types/bcryptjs": "^2.4.2",
20
+ "@types/busboy": "^1.5.0",
21
  "@types/lodash": "^4.14.188",
22
  "@types/marked": "^4.0.7",
23
+ "@types/sharp": "^0.31.0",
24
  "@typescript-eslint/eslint-plugin": "^5.27.0",
25
  "@typescript-eslint/parser": "^5.27.0",
26
  "@unocss/preset-icons": "^0.46.3",
 
43
  "type": "module",
44
  "dependencies": {
45
  "bcryptjs": "^2.4.3",
46
+ "busboy": "^1.6.0",
47
  "date-fns": "^2.29.3",
48
  "form-data": "^4.0.0",
49
  "lodash": "^4.17.21",
50
  "mailgun.js": "^8.0.2",
51
  "marked": "^4.2.2",
52
+ "mongodb": "^4.11.0",
53
+ "nanoid": "^4.0.0",
54
+ "sharp": "^0.31.2"
55
  }
56
  }
pnpm-lock.yaml CHANGED
@@ -6,14 +6,17 @@ specifiers:
6
  '@sveltejs/adapter-node': next
7
  '@sveltejs/kit': next
8
  '@types/bcryptjs': ^2.4.2
 
9
  '@types/lodash': ^4.14.188
10
  '@types/marked': ^4.0.7
 
11
  '@typescript-eslint/eslint-plugin': ^5.27.0
12
  '@typescript-eslint/parser': ^5.27.0
13
  '@unocss/preset-icons': ^0.46.3
14
  '@unocss/preset-uno': ^0.46.3
15
  '@unocss/reset': ^0.46.3
16
  bcryptjs: ^2.4.3
 
17
  date-fns: ^2.29.3
18
  eslint: ^8.16.0
19
  eslint-config-prettier: ^8.3.0
@@ -23,8 +26,10 @@ specifiers:
23
  mailgun.js: ^8.0.2
24
  marked: ^4.2.2
25
  mongodb: ^4.11.0
 
26
  prettier: ^2.6.2
27
  prettier-plugin-svelte: ^2.7.0
 
28
  svelte: ^3.44.0
29
  svelte-check: ^2.7.1
30
  svelte-preprocess: ^4.10.6
@@ -36,21 +41,26 @@ specifiers:
36
 
37
  dependencies:
38
  bcryptjs: 2.4.3
 
39
  date-fns: 2.29.3
40
  form-data: 4.0.0
41
  lodash: 4.17.21
42
  mailgun.js: 8.0.2
43
  marked: 4.2.2
44
  mongodb: 4.11.0
 
 
45
 
46
  devDependencies:
47
  '@iconify-json/ant-design': 1.1.3
48
  '@iconify-json/il': 1.1.2
49
  '@sveltejs/adapter-node': 1.0.0-next.100
50
- '@sveltejs/kit': 1.0.0-next.542_svelte@3.52.0+vite@3.2.2
51
  '@types/bcryptjs': 2.4.2
 
52
  '@types/lodash': 4.14.188
53
  '@types/marked': 4.0.7
 
54
  '@typescript-eslint/eslint-plugin': 5.42.0_6xw5wg2354iw4zujk2f3vyfrzu
55
  '@typescript-eslint/parser': 5.42.0_wyqvi574yv7oiwfeinomdzmc3m
56
  '@unocss/preset-icons': 0.46.3
@@ -1082,8 +1092,8 @@ packages:
1082
  rollup: 2.79.1
1083
  dev: true
1084
 
1085
- /@sveltejs/kit/1.0.0-next.542_svelte@3.52.0+vite@3.2.2:
1086
- resolution: {integrity: sha512-0YaNfrNsCwgCYuYEEKUF7G/QAkeGNJRlAFnPa9WTG2kRQPqlfUKOJlAniRHVG08ARdfNJgBSootWFvAUsKSoYA==}
1087
  engines: {node: '>=16.14'}
1088
  hasBin: true
1089
  requiresBuild: true
@@ -1136,6 +1146,12 @@ packages:
1136
  resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==}
1137
  dev: true
1138
 
 
 
 
 
 
 
1139
  /@types/cookie/0.5.1:
1140
  resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
1141
  dev: true
@@ -1177,6 +1193,12 @@ packages:
1177
  resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
1178
  dev: true
1179
 
 
 
 
 
 
 
1180
  /@types/webidl-conversions/7.0.0:
1181
  resolution: {integrity: sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==}
1182
  dev: false
@@ -1562,6 +1584,14 @@ packages:
1562
  engines: {node: '>=8'}
1563
  dev: true
1564
 
 
 
 
 
 
 
 
 
1565
  /bowser/2.11.0:
1566
  resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
1567
  dev: false
@@ -1615,7 +1645,6 @@ packages:
1615
  engines: {node: '>=10.16.0'}
1616
  dependencies:
1617
  streamsearch: 1.1.0
1618
- dev: true
1619
 
1620
  /cac/6.7.14:
1621
  resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
@@ -1650,16 +1679,33 @@ packages:
1650
  fsevents: 2.3.2
1651
  dev: true
1652
 
 
 
 
 
1653
  /color-convert/2.0.1:
1654
  resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
1655
  engines: {node: '>=7.0.0'}
1656
  dependencies:
1657
  color-name: 1.1.4
1658
- dev: true
1659
 
1660
  /color-name/1.1.4:
1661
  resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
1662
- dev: true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1663
 
1664
  /colorette/2.0.19:
1665
  resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
@@ -1723,6 +1769,18 @@ packages:
1723
  ms: 2.1.2
1724
  dev: true
1725
 
 
 
 
 
 
 
 
 
 
 
 
 
1726
  /deep-is/0.1.4:
1727
  resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
1728
  dev: true
@@ -1755,6 +1813,11 @@ packages:
1755
  engines: {node: '>=8'}
1756
  dev: true
1757
 
 
 
 
 
 
1758
  /devalue/4.2.0:
1759
  resolution: {integrity: sha512-mbjoAaCL2qogBKgeFxFPOXAUsZchircF+B/79LD4sHH0+NHfYm8gZpQrskKDn5gENGt35+5OI1GUF7hLVnkPDw==}
1760
  dev: true
@@ -1777,6 +1840,12 @@ packages:
1777
  resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
1778
  dev: true
1779
 
 
 
 
 
 
 
1780
  /es6-promise/3.3.1:
1781
  resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
1782
  dev: true
@@ -2156,6 +2225,11 @@ packages:
2156
  strip-final-newline: 2.0.0
2157
  dev: true
2158
 
 
 
 
 
 
2159
  /fast-deep-equal/3.1.3:
2160
  resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
2161
  dev: true
@@ -2246,6 +2320,10 @@ packages:
2246
  mime-types: 2.1.35
2247
  dev: false
2248
 
 
 
 
 
2249
  /fs.realpath/1.0.0:
2250
  resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
2251
  dev: true
@@ -2267,6 +2345,10 @@ packages:
2267
  engines: {node: '>=10'}
2268
  dev: true
2269
 
 
 
 
 
2270
  /glob-parent/5.1.2:
2271
  resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
2272
  engines: {node: '>= 6'}
@@ -2393,12 +2475,19 @@ packages:
2393
 
2394
  /inherits/2.0.4:
2395
  resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
2396
- dev: true
 
 
 
2397
 
2398
  /ip/2.0.0:
2399
  resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==}
2400
  dev: false
2401
 
 
 
 
 
2402
  /is-binary-path/2.1.0:
2403
  resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
2404
  engines: {node: '>=8'}
@@ -2526,7 +2615,6 @@ packages:
2526
  engines: {node: '>=10'}
2527
  dependencies:
2528
  yallist: 4.0.0
2529
- dev: true
2530
 
2531
  /magic-string/0.25.9:
2532
  resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
@@ -2606,6 +2694,11 @@ packages:
2606
  engines: {node: '>=6'}
2607
  dev: true
2608
 
 
 
 
 
 
2609
  /min-indent/1.0.1:
2610
  resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
2611
  engines: {node: '>=4'}
@@ -2626,7 +2719,10 @@ packages:
2626
 
2627
  /minimist/1.2.7:
2628
  resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==}
2629
- dev: true
 
 
 
2630
 
2631
  /mkdirp/0.5.6:
2632
  resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
@@ -2677,6 +2773,16 @@ packages:
2677
  hasBin: true
2678
  dev: true
2679
 
 
 
 
 
 
 
 
 
 
 
2680
  /natural-compare-lite/1.4.0:
2681
  resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
2682
  dev: true
@@ -2685,6 +2791,17 @@ packages:
2685
  resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
2686
  dev: true
2687
 
 
 
 
 
 
 
 
 
 
 
 
2688
  /node-fetch-native/0.1.8:
2689
  resolution: {integrity: sha512-ZNaury9r0NxaT2oL65GvdGDy+5PlSaHTovT6JV5tOW07k1TQmgC0olZETa4C9KZg0+6zBr99ctTYa3Utqj9P/Q==}
2690
  dev: true
@@ -2714,7 +2831,6 @@ packages:
2714
  resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
2715
  dependencies:
2716
  wrappy: 1.0.2
2717
- dev: true
2718
 
2719
  /onetime/5.1.2:
2720
  resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
@@ -2806,6 +2922,25 @@ packages:
2806
  source-map-js: 1.0.2
2807
  dev: true
2808
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2809
  /prelude-ls/1.2.1:
2810
  resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
2811
  engines: {node: '>= 0.8.0'}
@@ -2827,6 +2962,13 @@ packages:
2827
  hasBin: true
2828
  dev: true
2829
 
 
 
 
 
 
 
 
2830
  /punycode/2.1.1:
2831
  resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
2832
  engines: {node: '>=6'}
@@ -2835,6 +2977,25 @@ packages:
2835
  resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
2836
  dev: true
2837
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2838
  /readdirp/3.6.0:
2839
  resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
2840
  engines: {node: '>=8.10.0'}
@@ -2901,6 +3062,10 @@ packages:
2901
  mri: 1.2.0
2902
  dev: true
2903
 
 
 
 
 
2904
  /sander/0.5.1:
2905
  resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==}
2906
  dependencies:
@@ -2925,12 +3090,26 @@ packages:
2925
  hasBin: true
2926
  dependencies:
2927
  lru-cache: 6.0.0
2928
- dev: true
2929
 
2930
  /set-cookie-parser/2.5.1:
2931
  resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==}
2932
  dev: true
2933
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2934
  /shebang-command/2.0.0:
2935
  resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
2936
  engines: {node: '>=8'}
@@ -2947,6 +3126,24 @@ packages:
2947
  resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
2948
  dev: true
2949
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2950
  /sirv/2.0.2:
2951
  resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==}
2952
  engines: {node: '>= 10'}
@@ -3003,7 +3200,12 @@ packages:
3003
  /streamsearch/1.1.0:
3004
  resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
3005
  engines: {node: '>=10.0.0'}
3006
- dev: true
 
 
 
 
 
3007
 
3008
  /strip-ansi/6.0.1:
3009
  resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
@@ -3024,6 +3226,11 @@ packages:
3024
  min-indent: 1.0.1
3025
  dev: true
3026
 
 
 
 
 
 
3027
  /strip-json-comments/3.1.1:
3028
  resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
3029
  engines: {node: '>=8'}
@@ -3139,6 +3346,26 @@ packages:
3139
  engines: {node: '>= 8'}
3140
  dev: true
3141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3142
  /text-table/0.2.0:
3143
  resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
3144
  dev: true
@@ -3189,6 +3416,12 @@ packages:
3189
  typescript: 4.8.4
3190
  dev: true
3191
 
 
 
 
 
 
 
3192
  /type-check/0.4.0:
3193
  resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
3194
  engines: {node: '>= 0.8.0'}
@@ -3268,6 +3501,10 @@ packages:
3268
  resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==}
3269
  dev: false
3270
 
 
 
 
 
3271
  /uuid/8.3.2:
3272
  resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
3273
  hasBin: true
@@ -3332,11 +3569,9 @@ packages:
3332
 
3333
  /wrappy/1.0.2:
3334
  resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
3335
- dev: true
3336
 
3337
  /yallist/4.0.0:
3338
  resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
3339
- dev: true
3340
 
3341
  /yocto-queue/0.1.0:
3342
  resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
 
6
  '@sveltejs/adapter-node': next
7
  '@sveltejs/kit': next
8
  '@types/bcryptjs': ^2.4.2
9
+ '@types/busboy': ^1.5.0
10
  '@types/lodash': ^4.14.188
11
  '@types/marked': ^4.0.7
12
+ '@types/sharp': ^0.31.0
13
  '@typescript-eslint/eslint-plugin': ^5.27.0
14
  '@typescript-eslint/parser': ^5.27.0
15
  '@unocss/preset-icons': ^0.46.3
16
  '@unocss/preset-uno': ^0.46.3
17
  '@unocss/reset': ^0.46.3
18
  bcryptjs: ^2.4.3
19
+ busboy: ^1.6.0
20
  date-fns: ^2.29.3
21
  eslint: ^8.16.0
22
  eslint-config-prettier: ^8.3.0
 
26
  mailgun.js: ^8.0.2
27
  marked: ^4.2.2
28
  mongodb: ^4.11.0
29
+ nanoid: ^4.0.0
30
  prettier: ^2.6.2
31
  prettier-plugin-svelte: ^2.7.0
32
+ sharp: ^0.31.2
33
  svelte: ^3.44.0
34
  svelte-check: ^2.7.1
35
  svelte-preprocess: ^4.10.6
 
41
 
42
  dependencies:
43
  bcryptjs: 2.4.3
44
+ busboy: 1.6.0
45
  date-fns: 2.29.3
46
  form-data: 4.0.0
47
  lodash: 4.17.21
48
  mailgun.js: 8.0.2
49
  marked: 4.2.2
50
  mongodb: 4.11.0
51
+ nanoid: 4.0.0
52
+ sharp: 0.31.2
53
 
54
  devDependencies:
55
  '@iconify-json/ant-design': 1.1.3
56
  '@iconify-json/il': 1.1.2
57
  '@sveltejs/adapter-node': 1.0.0-next.100
58
+ '@sveltejs/kit': 1.0.0-next.544_svelte@3.52.0+vite@3.2.2
59
  '@types/bcryptjs': 2.4.2
60
+ '@types/busboy': 1.5.0
61
  '@types/lodash': 4.14.188
62
  '@types/marked': 4.0.7
63
+ '@types/sharp': 0.31.0
64
  '@typescript-eslint/eslint-plugin': 5.42.0_6xw5wg2354iw4zujk2f3vyfrzu
65
  '@typescript-eslint/parser': 5.42.0_wyqvi574yv7oiwfeinomdzmc3m
66
  '@unocss/preset-icons': 0.46.3
 
1092
  rollup: 2.79.1
1093
  dev: true
1094
 
1095
+ /@sveltejs/kit/1.0.0-next.544_svelte@3.52.0+vite@3.2.2:
1096
+ resolution: {integrity: sha512-zgQHiSvxiTDjJJROj9mPwIEoT6sAopagDroh89cHKarKc2eK/1nISA2dascKz/atGF8mghOn7RXZPnPofr01fQ==}
1097
  engines: {node: '>=16.14'}
1098
  hasBin: true
1099
  requiresBuild: true
 
1146
  resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==}
1147
  dev: true
1148
 
1149
+ /@types/busboy/1.5.0:
1150
+ resolution: {integrity: sha512-ncOOhwmyFDW76c/Tuvv9MA9VGYUCn8blzyWmzYELcNGDb0WXWLSmFi7hJq25YdRBYJrmMBB5jZZwUjlJe9HCjQ==}
1151
+ dependencies:
1152
+ '@types/node': 18.11.9
1153
+ dev: true
1154
+
1155
  /@types/cookie/0.5.1:
1156
  resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
1157
  dev: true
 
1193
  resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
1194
  dev: true
1195
 
1196
+ /@types/sharp/0.31.0:
1197
+ resolution: {integrity: sha512-nwivOU101fYInCwdDcH/0/Ru6yIRXOpORx25ynEOc6/IakuCmjOAGpaO5VfUl4QkDtUC6hj+Z2eCQvgXOioknw==}
1198
+ dependencies:
1199
+ '@types/node': 18.11.9
1200
+ dev: true
1201
+
1202
  /@types/webidl-conversions/7.0.0:
1203
  resolution: {integrity: sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==}
1204
  dev: false
 
1584
  engines: {node: '>=8'}
1585
  dev: true
1586
 
1587
+ /bl/4.1.0:
1588
+ resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
1589
+ dependencies:
1590
+ buffer: 5.7.1
1591
+ inherits: 2.0.4
1592
+ readable-stream: 3.6.0
1593
+ dev: false
1594
+
1595
  /bowser/2.11.0:
1596
  resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
1597
  dev: false
 
1645
  engines: {node: '>=10.16.0'}
1646
  dependencies:
1647
  streamsearch: 1.1.0
 
1648
 
1649
  /cac/6.7.14:
1650
  resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
 
1679
  fsevents: 2.3.2
1680
  dev: true
1681
 
1682
+ /chownr/1.1.4:
1683
+ resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
1684
+ dev: false
1685
+
1686
  /color-convert/2.0.1:
1687
  resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
1688
  engines: {node: '>=7.0.0'}
1689
  dependencies:
1690
  color-name: 1.1.4
 
1691
 
1692
  /color-name/1.1.4:
1693
  resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
1694
+
1695
+ /color-string/1.9.1:
1696
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
1697
+ dependencies:
1698
+ color-name: 1.1.4
1699
+ simple-swizzle: 0.2.2
1700
+ dev: false
1701
+
1702
+ /color/4.2.3:
1703
+ resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
1704
+ engines: {node: '>=12.5.0'}
1705
+ dependencies:
1706
+ color-convert: 2.0.1
1707
+ color-string: 1.9.1
1708
+ dev: false
1709
 
1710
  /colorette/2.0.19:
1711
  resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
 
1769
  ms: 2.1.2
1770
  dev: true
1771
 
1772
+ /decompress-response/6.0.0:
1773
+ resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
1774
+ engines: {node: '>=10'}
1775
+ dependencies:
1776
+ mimic-response: 3.1.0
1777
+ dev: false
1778
+
1779
+ /deep-extend/0.6.0:
1780
+ resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
1781
+ engines: {node: '>=4.0.0'}
1782
+ dev: false
1783
+
1784
  /deep-is/0.1.4:
1785
  resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
1786
  dev: true
 
1813
  engines: {node: '>=8'}
1814
  dev: true
1815
 
1816
+ /detect-libc/2.0.1:
1817
+ resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==}
1818
+ engines: {node: '>=8'}
1819
+ dev: false
1820
+
1821
  /devalue/4.2.0:
1822
  resolution: {integrity: sha512-mbjoAaCL2qogBKgeFxFPOXAUsZchircF+B/79LD4sHH0+NHfYm8gZpQrskKDn5gENGt35+5OI1GUF7hLVnkPDw==}
1823
  dev: true
 
1840
  resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
1841
  dev: true
1842
 
1843
+ /end-of-stream/1.4.4:
1844
+ resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
1845
+ dependencies:
1846
+ once: 1.4.0
1847
+ dev: false
1848
+
1849
  /es6-promise/3.3.1:
1850
  resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
1851
  dev: true
 
2225
  strip-final-newline: 2.0.0
2226
  dev: true
2227
 
2228
+ /expand-template/2.0.3:
2229
+ resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
2230
+ engines: {node: '>=6'}
2231
+ dev: false
2232
+
2233
  /fast-deep-equal/3.1.3:
2234
  resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
2235
  dev: true
 
2320
  mime-types: 2.1.35
2321
  dev: false
2322
 
2323
+ /fs-constants/1.0.0:
2324
+ resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
2325
+ dev: false
2326
+
2327
  /fs.realpath/1.0.0:
2328
  resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
2329
  dev: true
 
2345
  engines: {node: '>=10'}
2346
  dev: true
2347
 
2348
+ /github-from-package/0.0.0:
2349
+ resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
2350
+ dev: false
2351
+
2352
  /glob-parent/5.1.2:
2353
  resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
2354
  engines: {node: '>= 6'}
 
2475
 
2476
  /inherits/2.0.4:
2477
  resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
2478
+
2479
+ /ini/1.3.8:
2480
+ resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
2481
+ dev: false
2482
 
2483
  /ip/2.0.0:
2484
  resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==}
2485
  dev: false
2486
 
2487
+ /is-arrayish/0.3.2:
2488
+ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
2489
+ dev: false
2490
+
2491
  /is-binary-path/2.1.0:
2492
  resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
2493
  engines: {node: '>=8'}
 
2615
  engines: {node: '>=10'}
2616
  dependencies:
2617
  yallist: 4.0.0
 
2618
 
2619
  /magic-string/0.25.9:
2620
  resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
 
2694
  engines: {node: '>=6'}
2695
  dev: true
2696
 
2697
+ /mimic-response/3.1.0:
2698
+ resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
2699
+ engines: {node: '>=10'}
2700
+ dev: false
2701
+
2702
  /min-indent/1.0.1:
2703
  resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
2704
  engines: {node: '>=4'}
 
2719
 
2720
  /minimist/1.2.7:
2721
  resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==}
2722
+
2723
+ /mkdirp-classic/0.5.3:
2724
+ resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
2725
+ dev: false
2726
 
2727
  /mkdirp/0.5.6:
2728
  resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
 
2773
  hasBin: true
2774
  dev: true
2775
 
2776
+ /nanoid/4.0.0:
2777
+ resolution: {integrity: sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==}
2778
+ engines: {node: ^14 || ^16 || >=18}
2779
+ hasBin: true
2780
+ dev: false
2781
+
2782
+ /napi-build-utils/1.0.2:
2783
+ resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
2784
+ dev: false
2785
+
2786
  /natural-compare-lite/1.4.0:
2787
  resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
2788
  dev: true
 
2791
  resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
2792
  dev: true
2793
 
2794
+ /node-abi/3.28.0:
2795
+ resolution: {integrity: sha512-fRlDb4I0eLcQeUvGq7IY3xHrSb0c9ummdvDSYWfT9+LKP+3jCKw/tKoqaM7r1BAoiAC6GtwyjaGnOz6B3OtF+A==}
2796
+ engines: {node: '>=10'}
2797
+ dependencies:
2798
+ semver: 7.3.8
2799
+ dev: false
2800
+
2801
+ /node-addon-api/5.0.0:
2802
+ resolution: {integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==}
2803
+ dev: false
2804
+
2805
  /node-fetch-native/0.1.8:
2806
  resolution: {integrity: sha512-ZNaury9r0NxaT2oL65GvdGDy+5PlSaHTovT6JV5tOW07k1TQmgC0olZETa4C9KZg0+6zBr99ctTYa3Utqj9P/Q==}
2807
  dev: true
 
2831
  resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
2832
  dependencies:
2833
  wrappy: 1.0.2
 
2834
 
2835
  /onetime/5.1.2:
2836
  resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
 
2922
  source-map-js: 1.0.2
2923
  dev: true
2924
 
2925
+ /prebuild-install/7.1.1:
2926
+ resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
2927
+ engines: {node: '>=10'}
2928
+ hasBin: true
2929
+ dependencies:
2930
+ detect-libc: 2.0.1
2931
+ expand-template: 2.0.3
2932
+ github-from-package: 0.0.0
2933
+ minimist: 1.2.7
2934
+ mkdirp-classic: 0.5.3
2935
+ napi-build-utils: 1.0.2
2936
+ node-abi: 3.28.0
2937
+ pump: 3.0.0
2938
+ rc: 1.2.8
2939
+ simple-get: 4.0.1
2940
+ tar-fs: 2.1.1
2941
+ tunnel-agent: 0.6.0
2942
+ dev: false
2943
+
2944
  /prelude-ls/1.2.1:
2945
  resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
2946
  engines: {node: '>= 0.8.0'}
 
2962
  hasBin: true
2963
  dev: true
2964
 
2965
+ /pump/3.0.0:
2966
+ resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
2967
+ dependencies:
2968
+ end-of-stream: 1.4.4
2969
+ once: 1.4.0
2970
+ dev: false
2971
+
2972
  /punycode/2.1.1:
2973
  resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
2974
  engines: {node: '>=6'}
 
2977
  resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
2978
  dev: true
2979
 
2980
+ /rc/1.2.8:
2981
+ resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
2982
+ hasBin: true
2983
+ dependencies:
2984
+ deep-extend: 0.6.0
2985
+ ini: 1.3.8
2986
+ minimist: 1.2.7
2987
+ strip-json-comments: 2.0.1
2988
+ dev: false
2989
+
2990
+ /readable-stream/3.6.0:
2991
+ resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
2992
+ engines: {node: '>= 6'}
2993
+ dependencies:
2994
+ inherits: 2.0.4
2995
+ string_decoder: 1.3.0
2996
+ util-deprecate: 1.0.2
2997
+ dev: false
2998
+
2999
  /readdirp/3.6.0:
3000
  resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
3001
  engines: {node: '>=8.10.0'}
 
3062
  mri: 1.2.0
3063
  dev: true
3064
 
3065
+ /safe-buffer/5.2.1:
3066
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
3067
+ dev: false
3068
+
3069
  /sander/0.5.1:
3070
  resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==}
3071
  dependencies:
 
3090
  hasBin: true
3091
  dependencies:
3092
  lru-cache: 6.0.0
 
3093
 
3094
  /set-cookie-parser/2.5.1:
3095
  resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==}
3096
  dev: true
3097
 
3098
+ /sharp/0.31.2:
3099
+ resolution: {integrity: sha512-DUdNVEXgS5A97cTagSLIIp8dUZ/lZtk78iNVZgHdHbx1qnQR7JAHY0BnXnwwH39Iw+VKhO08CTYhIg0p98vQ5Q==}
3100
+ engines: {node: '>=14.15.0'}
3101
+ requiresBuild: true
3102
+ dependencies:
3103
+ color: 4.2.3
3104
+ detect-libc: 2.0.1
3105
+ node-addon-api: 5.0.0
3106
+ prebuild-install: 7.1.1
3107
+ semver: 7.3.8
3108
+ simple-get: 4.0.1
3109
+ tar-fs: 2.1.1
3110
+ tunnel-agent: 0.6.0
3111
+ dev: false
3112
+
3113
  /shebang-command/2.0.0:
3114
  resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
3115
  engines: {node: '>=8'}
 
3126
  resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
3127
  dev: true
3128
 
3129
+ /simple-concat/1.0.1:
3130
+ resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
3131
+ dev: false
3132
+
3133
+ /simple-get/4.0.1:
3134
+ resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
3135
+ dependencies:
3136
+ decompress-response: 6.0.0
3137
+ once: 1.4.0
3138
+ simple-concat: 1.0.1
3139
+ dev: false
3140
+
3141
+ /simple-swizzle/0.2.2:
3142
+ resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
3143
+ dependencies:
3144
+ is-arrayish: 0.3.2
3145
+ dev: false
3146
+
3147
  /sirv/2.0.2:
3148
  resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==}
3149
  engines: {node: '>= 10'}
 
3200
  /streamsearch/1.1.0:
3201
  resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
3202
  engines: {node: '>=10.0.0'}
3203
+
3204
+ /string_decoder/1.3.0:
3205
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
3206
+ dependencies:
3207
+ safe-buffer: 5.2.1
3208
+ dev: false
3209
 
3210
  /strip-ansi/6.0.1:
3211
  resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
 
3226
  min-indent: 1.0.1
3227
  dev: true
3228
 
3229
+ /strip-json-comments/2.0.1:
3230
+ resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
3231
+ engines: {node: '>=0.10.0'}
3232
+ dev: false
3233
+
3234
  /strip-json-comments/3.1.1:
3235
  resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
3236
  engines: {node: '>=8'}
 
3346
  engines: {node: '>= 8'}
3347
  dev: true
3348
 
3349
+ /tar-fs/2.1.1:
3350
+ resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
3351
+ dependencies:
3352
+ chownr: 1.1.4
3353
+ mkdirp-classic: 0.5.3
3354
+ pump: 3.0.0
3355
+ tar-stream: 2.2.0
3356
+ dev: false
3357
+
3358
+ /tar-stream/2.2.0:
3359
+ resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
3360
+ engines: {node: '>=6'}
3361
+ dependencies:
3362
+ bl: 4.1.0
3363
+ end-of-stream: 1.4.4
3364
+ fs-constants: 1.0.0
3365
+ inherits: 2.0.4
3366
+ readable-stream: 3.6.0
3367
+ dev: false
3368
+
3369
  /text-table/0.2.0:
3370
  resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
3371
  dev: true
 
3416
  typescript: 4.8.4
3417
  dev: true
3418
 
3419
+ /tunnel-agent/0.6.0:
3420
+ resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
3421
+ dependencies:
3422
+ safe-buffer: 5.2.1
3423
+ dev: false
3424
+
3425
  /type-check/0.4.0:
3426
  resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
3427
  engines: {node: '>= 0.8.0'}
 
3501
  resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==}
3502
  dev: false
3503
 
3504
+ /util-deprecate/1.0.2:
3505
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
3506
+ dev: false
3507
+
3508
  /uuid/8.3.2:
3509
  resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
3510
  hasBin: true
 
3569
 
3570
  /wrappy/1.0.2:
3571
  resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
 
3572
 
3573
  /yallist/4.0.0:
3574
  resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
 
3575
 
3576
  /yocto-queue/0.1.0:
3577
  resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
src/hooks.server.ts CHANGED
@@ -8,6 +8,13 @@ export const handle: Handle = async ({ event, resolve }) => {
8
  event.locals.user = await collections.users.findOne({ token });
9
  }
10
 
 
 
 
 
 
 
 
11
  const response = await resolve(event);
12
 
13
  return response;
 
8
  event.locals.user = await collections.users.findOne({ token });
9
  }
10
 
11
+ if (event.url.pathname.startsWith('/admin') && event.locals.user?.authority !== 'admin') {
12
+ return new Response('', {
13
+ status: 303,
14
+ headers: { location: `${event.url.protocol}//${event.url.host}` }
15
+ });
16
+ }
17
+
18
  const response = await resolve(event);
19
 
20
  return response;
src/lib/server/photo.ts ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sharp from 'sharp';
2
+ import { client, collections } from '$lib/server/db';
3
+ import { generateId } from '$lib/utils/generateId';
4
+ import type { ClientSession } from 'mongodb';
5
+ import { error } from '@sveltejs/kit';
6
+
7
+ export async function generatePicture(
8
+ buffer: Buffer,
9
+ name: string,
10
+ opts?: { productId?: string; cb?: (session: ClientSession) => Promise<void> }
11
+ ): Promise<void> {
12
+ const image = sharp(buffer);
13
+ const { width, height } = await image.metadata();
14
+
15
+ if (!width || !height) {
16
+ throw error(400, 'Invalid image: no height or width');
17
+ }
18
+
19
+ const formats: Array<{ width: number; height: number; data: Buffer }> = [];
20
+
21
+ if (width <= 2048 && height <= 2048) {
22
+ formats.push({
23
+ width,
24
+ height,
25
+ data: await image.toFormat('webp').toBuffer()
26
+ });
27
+ }
28
+
29
+ for (const size of [2048, 1024, 512]) {
30
+ if (width > size || height > size) {
31
+ const buffer = await image
32
+ .resize(width > height ? { width: size } : { height: size })
33
+ .toFormat('webp')
34
+ .toBuffer();
35
+ const metadata = await sharp(buffer).metadata();
36
+
37
+ formats.push({
38
+ width: metadata.width!,
39
+ height: metadata.height!,
40
+ data: buffer
41
+ });
42
+ }
43
+ }
44
+
45
+ const _id = generateId(name);
46
+
47
+ await client.withSession(async (session) => {
48
+ await collections.pictures.insertOne(
49
+ {
50
+ _id,
51
+ name,
52
+ storage: formats.map((format) => ({
53
+ _id: `${_id}-${format.width}x${format.height}`,
54
+ width: format.width,
55
+ height: format.height,
56
+ size: format.data.length
57
+ })),
58
+ ...(opts?.productId && { productId: opts.productId }),
59
+ createdAt: new Date(),
60
+ updatedAt: new Date()
61
+ },
62
+ { session }
63
+ );
64
+
65
+ await collections.picturesFs.insertMany(
66
+ formats.map(
67
+ (format) => ({
68
+ _id: `${_id}-${format.width}x${format.height}`,
69
+ createdAt: new Date(),
70
+ updatedAt: new Date(),
71
+ size: format.data.length,
72
+ data: format.data,
73
+ picture: _id
74
+ }),
75
+ { session }
76
+ )
77
+ );
78
+
79
+ if (opts?.cb) {
80
+ await opts.cb(session);
81
+ }
82
+ });
83
+ }
src/lib/server/utils/streamToBuffer.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Readable } from 'stream';
2
+
3
+ /**
4
+ * Reads a binary stream in memory and store it in a buffer
5
+ *
6
+ * @param stream The readable stream to read
7
+ * @returns {Buffer}
8
+ */
9
+ export async function streamToBuffer(stream: Readable): Promise<Buffer> {
10
+ const chunks: Buffer[] = [];
11
+ for await (const chunk of stream) {
12
+ chunks.push(chunk);
13
+ }
14
+
15
+ return Buffer.concat(chunks);
16
+ }
src/lib/utils/generateId.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import { kebabCase } from 'lodash';
2
+ import { nanoid } from 'nanoid';
3
+
4
+ export function generateId(name: string): string {
5
+ return kebabCase(name.replace(/&/g, '-and-')) + '-' + nanoid(6);
6
+ }
src/routes/admin/photos/+page.svelte CHANGED
@@ -5,7 +5,7 @@
5
  export let data: PageData;
6
  </script>
7
 
8
- <h1 class="text-sunray">Liste des photos</h1>
9
 
10
  <a href="/admin/photos/nouveau" class="my-4 block link">Nouvelle photo</a>
11
 
 
5
  export let data: PageData;
6
  </script>
7
 
8
+ <h1 class="text-sunray">Liste des photos sans produit</h1>
9
 
10
  <a href="/admin/photos/nouveau" class="my-4 block link">Nouvelle photo</a>
11
 
src/routes/admin/photos/nouveau/+page.server.ts ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Actions } from './$types';
2
+ import busboy from 'busboy';
3
+ import { pipeline } from 'node:stream';
4
+ import { streamToBuffer } from '$lib/server/utils/streamToBuffer';
5
+ import { generatePicture } from '$lib/server/photo';
6
+ import { redirect } from '@sveltejs/kit';
7
+
8
+ export const actions: Actions = {
9
+ default: async (input) => {
10
+ let buffer: Buffer;
11
+ let name = '';
12
+ let productId = '';
13
+
14
+ // eslint-disable-next-line no-async-promise-executor
15
+ await new Promise<void>(async (resolve, reject) => {
16
+ try {
17
+ const bb = busboy({
18
+ headers: {
19
+ 'content-type': input.request.headers.get('content-type') ?? undefined
20
+ }
21
+ });
22
+ bb.on('file', async (name, file, info) => {
23
+ // const { filename, encoding, mimeType } = info;
24
+ buffer = await streamToBuffer(file);
25
+ resolve();
26
+ });
27
+ bb.on('field', (_name, val) => {
28
+ if (_name === 'name') {
29
+ name = val;
30
+ } else if (_name === 'productId') {
31
+ productId = val;
32
+ }
33
+ });
34
+
35
+ await pipeline(input.request.body as any, bb, () => {});
36
+ } catch (err) {
37
+ reject(err);
38
+ }
39
+ });
40
+
41
+ await generatePicture(buffer, name, { productId: productId || undefined });
42
+
43
+ if (productId) {
44
+ throw redirect(303, '/admin/produits/' + productId);
45
+ }
46
+
47
+ throw redirect(303, '/admin/photos');
48
+ }
49
+ };
src/routes/admin/photos/nouveau/+page.svelte CHANGED
@@ -1,5 +1,4 @@
1
  <script lang="ts">
2
- import { enhance } from '$app/forms';
3
  import { page } from '$app/stores';
4
 
5
  const productId = $page.url.searchParams.get('productId');
@@ -7,7 +6,7 @@
7
 
8
  <h1 class="text-sunray">Ajouter une photo</h1>
9
 
10
- <form method="post" action="/admin/photos" enctype="multipart/form-data" use:enhance>
11
  <label class="block my-4 leading-8">
12
  Nom de la photo
13
  <input class="input block" type="text" name="name" placeholder="Nom définitif" required />
 
1
  <script lang="ts">
 
2
  import { page } from '$app/stores';
3
 
4
  const productId = $page.url.searchParams.get('productId');
 
6
 
7
  <h1 class="text-sunray">Ajouter une photo</h1>
8
 
9
+ <form method="post" enctype="multipart/form-data">
10
  <label class="block my-4 leading-8">
11
  Nom de la photo
12
  <input class="input block" type="text" name="name" placeholder="Nom définitif" required />
src/routes/admin/produits/[id]/+page.server.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { collections } from '$lib/server/db';
2
  import type { Product } from '$lib/types/Product';
3
- import { error } from '@sveltejs/kit';
4
  import type { Actions, PageServerLoad } from './$types';
5
  import { omit } from 'lodash';
6
 
@@ -23,7 +23,7 @@ export const load: PageServerLoad = async ({ params }) => {
23
  };
24
 
25
  export const actions: Actions = {
26
- default: async ({ request, params }) => {
27
  const formData = await request.formData();
28
 
29
  const update = {
@@ -48,5 +48,32 @@ export const actions: Actions = {
48
  }
49
 
50
  return {};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  }
52
  };
 
1
+ import { client, collections, db } from '$lib/server/db';
2
  import type { Product } from '$lib/types/Product';
3
+ import { error, redirect } from '@sveltejs/kit';
4
  import type { Actions, PageServerLoad } from './$types';
5
  import { omit } from 'lodash';
6
 
 
23
  };
24
 
25
  export const actions: Actions = {
26
+ update: async ({ request, params }) => {
27
  const formData = await request.formData();
28
 
29
  const update = {
 
48
  }
49
 
50
  return {};
51
+ },
52
+
53
+ delete: async ({ params }) => {
54
+ await client.withSession(async (session) => {
55
+ const product = await collections.products.findOneAndDelete({ _id: params.id });
56
+
57
+ if (!product.value) {
58
+ throw error(404);
59
+ }
60
+
61
+ const pictures = await collections.pictures
62
+ .find({ productId: params.id }, { session })
63
+ .toArray();
64
+
65
+ await collections.pictures.deleteMany(
66
+ { _id: { $in: pictures.map((p) => p._id) } },
67
+ { session }
68
+ );
69
+ await collections.picturesFs.deleteMany(
70
+ {
71
+ _id: { $in: pictures.flatMap((p) => p.storage.map((s) => s._id)) }
72
+ },
73
+ { session }
74
+ );
75
+ });
76
+
77
+ throw redirect(303, '/admin/produits');
78
  }
79
  };
src/routes/admin/produits/[id]/+page.svelte CHANGED
@@ -8,7 +8,7 @@
8
  <h1 class="text-sunray">Modifier un produit</h1>
9
 
10
  <div class="flex flex-col">
11
- <form method="post">
12
  <label class="block w-full mt-4 leading-8">
13
  Nom
14
  <input type="text" name="name" class="input block" value={data.product.name} />
@@ -45,6 +45,7 @@
45
  </label>
46
 
47
  <button type="submit" class="mt-4 btn">Valider</button>
 
48
  </form>
49
  </div>
50
 
 
8
  <h1 class="text-sunray">Modifier un produit</h1>
9
 
10
  <div class="flex flex-col">
11
+ <form method="post" action="?/update">
12
  <label class="block w-full mt-4 leading-8">
13
  Nom
14
  <input type="text" name="name" class="input block" value={data.product.name} />
 
45
  </label>
46
 
47
  <button type="submit" class="mt-4 btn">Valider</button>
48
+ <button type="submit" class="mt-4 btn-red float-right" formaction="?/delete">Supprimer</button>
49
  </form>
50
  </div>
51
 
src/routes/admin/produits/nouveau/+page.server.ts ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { collections } from '$lib/server/db';
2
+ import { generatePicture } from '$lib/server/photo';
3
+ import type { Product } from '$lib/types/Product';
4
+ import { generateId } from '$lib/utils/generateId';
5
+ import type { Actions } from './$types';
6
+ import { pipeline } from 'node:stream';
7
+ import busboy from 'busboy';
8
+ import { streamToBuffer } from '$lib/server/utils/streamToBuffer';
9
+ import { redirect } from '@sveltejs/kit';
10
+
11
+ export const actions: Actions = {
12
+ default: async ({ request }) => {
13
+ let buffer: Buffer;
14
+
15
+ const fields = {
16
+ name: '',
17
+ description: '',
18
+ price: 100,
19
+ kind: 'armchair'
20
+ };
21
+
22
+ // eslint-disable-next-line no-async-promise-executor
23
+ await new Promise<void>(async (resolve, reject) => {
24
+ try {
25
+ const bb = busboy({
26
+ headers: {
27
+ 'content-type': request.headers.get('content-type') ?? undefined
28
+ }
29
+ });
30
+ bb.on('file', async (name, file, info) => {
31
+ // const { filename, encoding, mimeType } = info;
32
+ buffer = await streamToBuffer(file);
33
+ resolve();
34
+ });
35
+ bb.on('field', (name, val) => {
36
+ if (name in fields) {
37
+ fields[name] = val;
38
+ }
39
+ });
40
+
41
+ await pipeline(request.body as any, bb, () => {});
42
+ } catch (err) {
43
+ reject(err);
44
+ }
45
+ });
46
+
47
+ const productId = generateId(fields.name);
48
+
49
+ await generatePicture(buffer, fields.name, {
50
+ productId,
51
+ cb: async (session) => {
52
+ await collections.products.insertOne(
53
+ {
54
+ _id: productId,
55
+ createdAt: new Date(),
56
+ updatedAt: new Date(),
57
+ description: fields.description.replaceAll('\r', ''),
58
+ kind: fields.kind as Product['kind'],
59
+ name: fields.name,
60
+ price: +fields.price,
61
+ photos: [],
62
+ state: 'draft'
63
+ },
64
+ { session }
65
+ );
66
+ }
67
+ });
68
+
69
+ throw redirect(303, '/admin/produits/' + productId);
70
+ }
71
+ };
src/routes/admin/produits/nouveau/+page.svelte CHANGED
@@ -1,6 +1,6 @@
1
  <h1 class="text-sunray">Ajouter un produit</h1>
2
 
3
- <form method="post" enctype="multipart/form-data" action="/admin/produits">
4
  <label class="block my-4 leading-8">
5
  Nom du produit
6
  <input class="input block" type="text" name="name" placeholder="Nom définitif" required />
@@ -23,7 +23,7 @@
23
 
24
  <label class="block my-4 leading-8">
25
  Type
26
- <select name="kind">
27
  <option value="armchair">Fauteuil</option>
28
  <option value="chair">Chaise</option>
29
  <option value="couch">Canapé</option>
 
1
  <h1 class="text-sunray">Ajouter un produit</h1>
2
 
3
+ <form method="post" enctype="multipart/form-data">
4
  <label class="block my-4 leading-8">
5
  Nom du produit
6
  <input class="input block" type="text" name="name" placeholder="Nom définitif" required />
 
23
 
24
  <label class="block my-4 leading-8">
25
  Type
26
+ <select name="kind" class="input">
27
  <option value="armchair">Fauteuil</option>
28
  <option value="chair">Chaise</option>
29
  <option value="couch">Canapé</option>
vite.config.ts CHANGED
@@ -28,6 +28,7 @@ const config: UserConfig = {
28
  input: 'w-full max-w-80 text-lg pl-2 border border-solid border-2 rounded-xl',
29
  link: 'underline text-brunswick',
30
  btn: 'text-white bg-oxford px-4 py-2 rounded-3xl font-bold border-0 cursor-pointer',
 
31
  'btn-sunray': 'text-white bg-sunray px-4 py-2 rounded-3xl font-bold border-0 cursor-pointer'
32
  },
33
  theme: {
 
28
  input: 'w-full max-w-80 text-lg pl-2 border border-solid border-2 rounded-xl',
29
  link: 'underline text-brunswick',
30
  btn: 'text-white bg-oxford px-4 py-2 rounded-3xl font-bold border-0 cursor-pointer',
31
+ 'btn-red': 'text-white bg-red-500 px-4 py-2 rounded-3xl font-bold border-0 cursor-pointer',
32
  'btn-sunray': 'text-white bg-sunray px-4 py-2 rounded-3xl font-bold border-0 cursor-pointer'
33
  },
34
  theme: {