Compare commits

...

7 Commits

Author SHA1 Message Date
06fef791e5 Merge branch 'add-link' 2024-02-10 10:25:27 -05:00
cc3d4c1474 add a link to the game itself 2024-02-10 10:25:02 -05:00
98397bfbc6 Merge branch 'cart' 2024-02-10 10:20:37 -05:00
ef1e9c9ae8 add a test 2024-02-10 10:19:56 -05:00
a1bab69ee8 Merge branch 'favicon' 2024-02-09 16:00:02 -05:00
c64091af19 work on task integrate 2024-02-09 15:59:42 -05:00
3eaa100a49 add favicon 2024-02-09 15:58:55 -05:00
19 changed files with 508 additions and 31 deletions

View File

@ -10,7 +10,8 @@ tasks:
integrate:
deps: [is-clean, test]
cmds:
- echo "do something"
- git checkout main
- git weld - --no-edit
test:unit:
cmds:
- vitest run

View File

@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
for (const url of ['/', '/stats/', '/about/']) {
for (const url of ['/', '/stats/', '/about/', '/cart/']) {
test(url + ' render', async ({ page }) => {
await page.goto(url);
await expect(

104
favicon/favicon.svg Normal file
View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:serif="http://www.serif.com/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1200pt"
height="1200pt"
version="1.1"
viewBox="0 0 1200 1200"
id="svg4"
sodipodi:docname="favicon.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
inkscape:export-filename="/home/yanick/work/javascript/ottawa-boardgame-sell-bgg/favicon/favicon.png"
inkscape:export-xdpi="3.8399999"
inkscape:export-ydpi="3.8399999">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1084"
inkscape:window-height="807"
id="namedview6"
showgrid="false"
inkscape:zoom="0.1475"
inkscape:cx="1719.5047"
inkscape:cy="800"
inkscape:window-x="145"
inkscape:window-y="84"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<path
d="m1199.9 516.23c6.9375-165.09-388.25-245.46-405.37-264.28-8.5312-9.3555 19.801-252.13-194.53-251.95-214.33-0.17969-186.01 242.59-194.54 251.95-17.125 18.816-412.29 99.191-405.36 264.28 6.9102 165.1 216.61 80.305 261.34 128.89 39.121 42.527-183.35 314.75-208.23 487.61-8.1133 56.336 7.7266 67.27 62.48 67.27 99.312 0 194.12-0.058594 281.44-0.058594 39.445 0 53.473-22.668 73.824-53.902 45.047-69.148 99.453-180.29 129.06-180.28 29.594-0.011719 84.012 111.13 129.06 180.27 20.352 31.246 34.367 53.902 73.812 53.902 87.301 0 182.12 0.058593 281.44 0.058593 54.758 0 70.609-10.934 62.484-67.273-24.875-172.86-247.33-445.08-208.23-487.61 44.723-48.574 254.45 36.219 261.34-128.88z"
fill-rule="evenodd"
id="path2"
style="fill:#be0003;fill-opacity:1" />
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Layer 1"
style="display:inline">
<rect
serif:id="trading changer"
x="1288.6348"
y="76.701424"
width="1150.5254"
height="1150.5254"
style="fill:none;stroke-width:35.95391846"
id="rect12" />
<path
inkscape:connector-curvature="0"
d="m 853.24685,471.88905 -58.42019,58.44401 -0.98518,1.04287 c -0.81537,0.96812 -1.05301,1.19912 -1.80039,2.21818 -9.75929,13.75754 -1.39271,36.8396 16.50903,39.87136 7.97249,1.34859 16.32897,-1.45048 22.29046,-7.10805 L 932.77549,464.4498 c 4.96628,-5.24825 7.616,-12.12702 7.41212,-19.46435 -0.5095,-6.21637 -3.09116,-12.02508 -7.41212,-16.58546 L 830.84058,326.4669 c -0.91697,-0.86622 -1.12084,-1.09721 -2.10587,-1.91246 -11.08424,-8.81502 -29.73335,-5.96161 -37.47828,6.36921 -6.08723,9.68123 -4.43304,23.13304 3.56672,31.59136 l 58.4202,58.41855 H 303.19701 c -9.55547,1.07003 -18.75094,5.68135 -22.95634,14.41992 -4.9935,10.39459 -1.93629,23.8209 7.05881,30.97991 4.4568,3.56678 10.13985,4.91704 15.89753,5.55397 z m -488.5214,305.79926 h 550.04641 c 9.52836,-1.07005 18.75097,-5.68132 22.95635,-14.4199 2.20799,-4.63679 1.97038,-6.06348 2.51368,-11.05698 -0.33964,-1.88531 -0.44143,-3.79607 -0.6454,-5.68136 -1.25691,-3.59224 -2.54762,-7.26092 -4.9187,-10.21624 -3.59044,-4.50941 -8.71318,-7.69402 -14.26699,-8.94238 -1.8344,-0.43482 -3.77067,-0.43482 -5.656,-0.63863 H 364.70849 l 58.42027,-58.44401 c 0,0 7.69397,-9.91052 7.4121,-19.43888 0,-1.27384 0,-1.57956 -0.33969,-2.8534 -2.41181,-14.06326 -18.29254,-24.20307 -32.17564,-20.20319 -2.7515,0.78808 -5.37736,2.03814 -7.69398,3.69413 -1.15507,0.84245 -2.242,1.78338 -3.29501,2.7753 L 285.12883,734.17038 c -0.8832,0.94094 -1.12092,1.14477 -1.9023,2.14006 -7.1096,8.91692 -7.26261,22.69992 0,31.7697 0.78138,0.9919 1.0191,1.2229 1.9023,2.14004 l 101.90771,101.93307 c 0.95111,0.86626 1.15491,1.09727 2.13994,1.91239 13.47909,10.72586 37.78393,3.2849 41.01789,-15.66823 1.35879,-7.97419 -1.46077,-16.30522 -7.10647,-22.29219 z"
style="fill:#f9ffff;fill-opacity:1;fill-rule:nonzero;stroke-width:25.4769001"
id="path14" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2"
style="display:none">
<path
inkscape:connector-curvature="0"
d="m 753.00177,630.60031 c -1.2634,-5.24653 -5.9554,-8.93708 -11.3416,-8.93708 h -50.9987 V 546.6353 c 0,-30.12281 -24.508,-54.63003 -54.6308,-54.63003 h -70.2202 c -30.1228,0 -54.6294,24.50722 -54.6294,54.63003 v 75.02793 h -51 c -5.3862,0 -10.0742,3.69055 -11.3309,8.93708 l -67.5869,281.06022 c -2.7331,11.3509 0.012,22.662 7.9197,32.7062 12.9668,16.4579 39.29,27.5096 65.5228,27.5096 h 292.451 c 26.2222,0 52.5547,-11.0517 65.5215,-27.5096 7.9104,-10.0343 10.6435,-21.3454 7.9197,-32.6962 z M 534.50137,546.6353 c 0,-17.26567 14.0441,-31.30973 31.3091,-31.30973 h 70.2202 c 17.2665,0 31.3105,14.04406 31.3105,31.30973 v 75.02793 h -132.8398 z m 259.8546,383.28843 c -8.638,10.9619 -28.0482,18.6223 -47.2099,18.6223 h -292.4509 c -19.151,0 -38.5706,-7.6604 -47.2085,-18.6223 -3.4219,-4.3488 -4.5882,-8.5381 -3.5616,-12.8172 l 65.4431,-272.12301 h 41.8129 v 33.08523 c -12.359,4.7179 -21.1764,16.66733 -21.1764,30.66146 0,18.10367 14.733,32.83593 32.8359,32.83593 18.1043,0 32.8359,-14.73226 32.8359,-32.83593 0,-13.99413 -8.8174,-25.94356 -21.1751,-30.66146 v -33.08523 h 132.8398 v 33.08523 c -12.359,4.7179 -21.1765,16.66733 -21.1765,30.66146 0,18.10367 14.733,32.83593 32.836,32.83593 18.1043,0 32.8359,-14.73226 32.8359,-32.83593 0,-13.99413 -8.8174,-25.94356 -21.1751,-30.66146 v -33.08523 h 41.8129 l 65.4417,272.12301 c 1.0241,4.2791 -0.1463,8.4684 -3.5601,12.8172 z M 522.84057,699.21457 c 5.2465,0 9.5157,4.26911 9.5157,9.51564 0,5.24653 -4.2692,9.51564 -9.5157,9.51564 -5.2465,0 -9.5156,-4.26911 -9.5156,-9.51564 0,-5.24653 4.2691,-9.51564 9.5156,-9.51564 z m 156.1601,0 c 5.2465,0 9.5156,4.26911 9.5156,9.51564 0,5.24653 -4.2691,9.51564 -9.5156,9.51564 -5.2466,0 -9.5157,-4.26911 -9.5157,-9.51564 0,-5.24653 4.2691,-9.51564 9.5157,-9.51564 z m -78.08,-289.24919 c 92.5828,0 167.9006,-75.31711 167.9006,-167.89999 0,-92.58288 -75.3178,-167.899989 -167.9006,-167.899989 -92.5829,0 -167.8994,75.317109 -167.8994,167.899989 0,92.58288 75.3165,167.89999 167.8994,167.89999 z m 0,-312.479699 c 79.7264,0 144.5803,64.863869 144.5803,144.579709 0,79.72581 -64.8645,144.57972 -144.5803,144.57972 -79.7252,0 -144.5791,-64.86388 -144.5791,-144.57972 0,-79.72582 64.8539,-144.579709 144.5791,-144.579709 z m -11.6595,155.342149 v 55.74722 c -9.0875,-1.99489 -16.9965,-6.30385 -22.243,-12.34837 -4.2199,-4.85757 -11.5811,-5.38621 -16.4485,-1.16768 -4.8676,4.2192 -5.3863,11.58034 -1.1704,16.44788 9.4956,10.94197 23.8789,18.32307 39.8579,20.75683 v 10.09416 c 0,6.43351 5.216,11.66013 11.6594,11.66013 6.4435,0 11.6608,-5.21664 11.6608,-11.66013 v -10.10413 c 29.2146,-4.46855 51.3884,-25.39496 51.3884,-50.48072 0,-25.08574 -22.1738,-46.01215 -51.3884,-50.4807 v -55.74723 c 9.0861,1.99489 16.9965,6.30386 22.243,12.34838 4.2186,4.86753 11.5798,5.3862 16.4473,1.16766 4.8675,-4.21918 5.3862,-11.58033 1.1703,-16.44786 -9.4956,-10.94198 -23.8788,-18.31311 -39.8578,-20.75685 v -10.09414 c 0,-6.43353 -5.2173,-11.66013 -11.6608,-11.66013 -6.4436,0 -11.6595,5.21663 -11.6595,11.66013 v 10.10412 c -29.2052,4.46856 -51.3884,25.39496 -51.3884,50.48071 0,25.08576 22.1832,46.01216 51.3884,50.48072 z m 51.3884,28.95583 c 0,12.35836 -12.0093,23.16069 -28.0681,26.77144 v -53.54287 c 16.0588,3.61076 28.0681,14.41309 28.0681,26.77143 z m -51.3884,-106.19801 v 53.54287 c -16.0588,-3.61075 -28.0681,-14.41309 -28.0681,-26.77143 0,-12.35835 12.0093,-23.16069 28.0681,-26.77144 z M 1043.5071,454.36167 889.77157,334.72807 c -3.5217,-2.733 -8.2788,-3.22175 -12.2792,-1.27673 -3.9992,1.955 -6.5326,6.02457 -6.5326,10.47318 v 56.24594 h -154.8634 c -6.4343,0 -11.6608,5.21665 -11.6608,11.66015 v 103.44503 c 0,6.43357 5.2172,11.6602 11.6608,11.6602 h 154.8634 v 56.24596 c 0,4.44857 2.5334,8.51819 6.5326,10.47316 1.6264,0.79795 3.3819,1.18633 5.1175,1.18633 2.5428,0 5.0763,-0.83788 7.1617,-2.45381 l 153.73553,-119.6236 c 2.8434,-2.20435 4.4992,-5.60565 4.4992,-9.19644 0,-3.59081 -1.6558,-7.00207 -4.4992,-9.20642 z M 894.26927,559.34276 v -44.05711 c 0,-6.43358 -5.2159,-11.66009 -11.6594,-11.66009 h -154.8634 v -80.12484 h 154.8634 c 6.4328,0 11.6594,-5.21665 11.6594,-11.66014 V 367.78341 L 1017.3648,463.5681 Z M 497.40577,515.28565 V 411.83061 c 0,-6.43353 -5.216,-11.66015 -11.6595,-11.66015 h -154.8634 v -56.24594 c 0,-4.44861 -2.5335,-8.51818 -6.5339,-10.47318 -3.9991,-1.95499 -8.7669,-1.46625 -12.2778,1.27673 l -153.737,119.6336 c -2.8421,2.20436 -4.4978,5.60565 -4.4978,9.19646 0,3.5908 1.6557,6.99208 4.4978,9.19644 l 153.737,119.62361 c 2.0839,1.62582 4.6174,2.45369 7.1615,2.45369 1.7449,0 3.4911,-0.38825 5.1163,-1.18621 4.0004,-1.95508 6.5339,-6.02458 6.5339,-10.47316 v -56.24595 h 154.8634 c 6.4435,0.0119 11.6595,-5.20673 11.6595,-11.64019 z m -23.3097,-11.66009 h -154.874 c -6.4328,0 -11.6595,5.21662 -11.6595,11.66009 v 44.05711 l -123.0847,-95.78463 123.094,-95.7847 v 44.05718 c 0,6.43351 5.2174,11.66013 11.6608,11.66013 h 154.8634 z"
id="path1517"
style="fill:#be0003;fill-opacity:1;stroke-width:9.97445393" />
<text
style="font-weight:bold;font-size:49.87227249px;font-family:'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif;fill:#be0003;fill-opacity:1;stroke-width:9.97445393"
x="1469.6041"
y="1248.0165"
font-size="5px"
font-weight="bold"
id="text1519">Created by miftahul huda</text>
<text
style="font-weight:bold;font-size:49.87227249px;font-family:'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif;fill:#be0003;fill-opacity:1;stroke-width:9.97445393"
x="1469.6041"
y="1297.8888"
font-size="5px"
font-weight="bold"
id="text1521">from the Noun Project</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

1
favicon/link.md Normal file
View File

@ -0,0 +1 @@
Trade by Bombasticon Studio from <a href="https://thenounproject.com/browse/icons/term/trade/" target="_blank" title="Trade Icons">Noun Project</a> (CC BY 3.0)

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
<path d="m1199.9 516.23c6.9375-165.09-388.25-245.46-405.37-264.28-8.5312-9.3555 19.801-252.13-194.53-251.95-214.33-0.17969-186.01 242.59-194.54 251.95-17.125 18.816-412.29 99.191-405.36 264.28 6.9102 165.1 216.61 80.305 261.34 128.89 39.121 42.527-183.35 314.75-208.23 487.61-8.1133 56.336 7.7266 67.27 62.48 67.27 99.312 0 194.12-0.058594 281.44-0.058594 39.445 0 53.473-22.668 73.824-53.902 45.047-69.148 99.453-180.29 129.06-180.28 29.594-0.011719 84.012 111.13 129.06 180.27 20.352 31.246 34.367 53.902 73.812 53.902 87.301 0 182.12 0.058593 281.44 0.058593 54.758 0 70.609-10.934 62.484-67.273-24.875-172.86-247.33-445.08-208.23-487.61 44.723-48.574 254.45 36.219 261.34-128.88z" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 864 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:serif="http://www.serif.com/" viewBox="0 0 32 40" version="1.1" xml:space="preserve" style="" x="0px" y="0px" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.41421"><rect serif:id="trading changer" x="0" y="0" width="32" height="32" style="" fill="none"/><path d="M25.585,11.002l-2.293,2.294l-0.039,0.041c-0.032,0.038 -0.041,0.047 -0.07,0.087c-0.383,0.54 -0.055,1.446 0.648,1.565c0.313,0.053 0.641,-0.057 0.875,-0.279l4.001,-4c0.195,-0.206 0.299,-0.476 0.291,-0.764c-0.02,-0.244 -0.122,-0.472 -0.291,-0.651l-4.001,-4.001c-0.036,-0.034 -0.044,-0.043 -0.083,-0.075c-0.435,-0.346 -1.167,-0.234 -1.471,0.25c-0.239,0.38 -0.174,0.908 0.14,1.24l2.293,2.293l-21.59,0c-0.375,0.042 -0.736,0.223 -0.901,0.566c-0.196,0.408 -0.076,0.935 0.277,1.216c0.175,0.14 0.398,0.193 0.624,0.218l21.59,0Zm-19.175,12.003l21.59,0c0.374,-0.042 0.736,-0.223 0.901,-0.566c0.087,-0.182 0.077,-0.238 0.099,-0.434c-0.008,-0.074 -0.017,-0.149 -0.025,-0.223c-0.05,-0.141 -0.1,-0.285 -0.193,-0.401c-0.141,-0.177 -0.342,-0.302 -0.56,-0.351c-0.072,-0.017 -0.148,-0.017 -0.222,-0.025l-21.59,0l2.293,-2.294c0,0 0.302,-0.389 0.291,-0.763c-0.004,-0.05 -0.004,-0.062 -0.012,-0.112c-0.094,-0.552 -0.718,-0.95 -1.263,-0.793c-0.108,0.031 -0.211,0.08 -0.302,0.145c-0.046,0.033 -0.088,0.07 -0.129,0.109l-4,4c-0.035,0.037 -0.044,0.045 -0.075,0.084c-0.279,0.35 -0.285,0.891 0,1.247c0.031,0.039 0.04,0.048 0.075,0.084l4,4.001c0.037,0.034 0.045,0.043 0.084,0.075c0.529,0.421 1.483,0.129 1.61,-0.615c0.053,-0.313 -0.058,-0.64 -0.279,-0.875l-2.293,-2.293Z" style="" fill-rule="nonzero"/><text x="0" y="47" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">Created by Bombasticon Studio</text><text x="0" y="52" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">from the Noun Project</text></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 96 120" style="enable-background:new 0 0 96 96;" xml:space="preserve"><path d="M63.247,58.786C63.12,58.26,62.65,57.89,62.11,57.89h-5.113v-7.522c0-3.02-2.457-5.477-5.477-5.477h-7.04 c-3.02,0-5.477,2.457-5.477,5.477v7.522H33.89c-0.54,0-1.01,0.37-1.136,0.896l-6.776,28.178c-0.274,1.138,0.001,2.272,0.794,3.279 c1.3,1.65,3.939,2.758,6.569,2.758h29.32c2.629,0,5.269-1.108,6.569-2.758c0.793-1.006,1.067-2.14,0.794-3.278L63.247,58.786z M41.341,50.368c0-1.731,1.408-3.139,3.139-3.139h7.04c1.731,0,3.139,1.408,3.139,3.139v7.522H41.341V50.368z M67.393,88.795 c-0.866,1.099-2.812,1.867-4.733,1.867H33.34c-1.92,0-3.867-0.768-4.733-1.867c-0.343-0.436-0.46-0.856-0.357-1.285l6.561-27.282 h4.192v3.317c-1.239,0.473-2.123,1.671-2.123,3.074c0,1.815,1.477,3.292,3.292,3.292s3.292-1.477,3.292-3.292 c0-1.403-0.884-2.601-2.123-3.074v-3.317h13.318v3.317c-1.239,0.473-2.123,1.671-2.123,3.074c0,1.815,1.477,3.292,3.292,3.292 s3.292-1.477,3.292-3.292c0-1.403-0.884-2.601-2.123-3.074v-3.317h4.192L67.75,87.51C67.853,87.939,67.736,88.359,67.393,88.795z M40.172,65.665c0.526,0,0.954,0.428,0.954,0.954c0,0.526-0.428,0.954-0.954,0.954s-0.954-0.428-0.954-0.954 C39.218,66.093,39.646,65.665,40.172,65.665z M55.828,65.665c0.526,0,0.954,0.428,0.954,0.954c0,0.526-0.428,0.954-0.954,0.954 s-0.954-0.428-0.954-0.954C54.874,66.093,55.302,65.665,55.828,65.665z M48,36.666c9.282,0,16.833-7.551,16.833-16.833 S57.282,3,48,3s-16.833,7.551-16.833,16.833S38.718,36.666,48,36.666z M48,5.338c7.993,0,14.495,6.503,14.495,14.495 c0,7.993-6.503,14.495-14.495,14.495c-7.993,0-14.495-6.503-14.495-14.495C33.505,11.84,40.007,5.338,48,5.338z M46.831,20.912 v5.589c-0.911-0.2-1.704-0.632-2.23-1.238c-0.423-0.487-1.161-0.54-1.649-0.117c-0.488,0.423-0.54,1.161-0.117,1.649 c0.952,1.097,2.394,1.837,3.996,2.081v1.012c0,0.645,0.523,1.169,1.169,1.169s1.169-0.523,1.169-1.169v-1.013 c2.929-0.448,5.152-2.546,5.152-5.061s-2.223-4.613-5.152-5.061v-5.589c0.911,0.2,1.704,0.632,2.23,1.238 c0.423,0.488,1.161,0.54,1.649,0.117c0.488-0.423,0.54-1.161,0.117-1.649c-0.952-1.097-2.394-1.836-3.996-2.081V9.777 c0-0.645-0.523-1.169-1.169-1.169s-1.169,0.523-1.169,1.169v1.013c-2.928,0.448-5.152,2.546-5.152,5.061 C41.679,18.366,43.903,20.464,46.831,20.912z M51.983,23.815c0,1.239-1.204,2.322-2.814,2.684v-5.368 C50.779,21.493,51.983,22.576,51.983,23.815z M46.831,13.168v5.368c-1.61-0.362-2.814-1.445-2.814-2.684 C44.017,14.613,45.221,13.53,46.831,13.168z M92.372,41.117L76.959,29.123c-0.353-0.274-0.83-0.323-1.231-0.128 c-0.401,0.196-0.655,0.604-0.655,1.05v5.639H59.547c-0.645,0-1.169,0.523-1.169,1.169v10.371c0,0.645,0.523,1.169,1.169,1.169 h15.526v5.639c0,0.446,0.254,0.854,0.655,1.05c0.163,0.08,0.339,0.119,0.513,0.119c0.255,0,0.509-0.084,0.718-0.246l15.413-11.993 c0.285-0.221,0.451-0.562,0.451-0.922S92.657,41.338,92.372,41.117z M77.41,51.642v-4.417c0-0.645-0.523-1.169-1.169-1.169H60.715 v-8.033h15.526c0.645,0,1.169-0.523,1.169-1.169v-4.417l12.341,9.603L77.41,51.642z M37.622,47.225V36.853 c0-0.645-0.523-1.169-1.169-1.169H20.927v-5.639c0-0.446-0.254-0.854-0.655-1.05c-0.401-0.196-0.879-0.147-1.231,0.128L3.628,41.117 c-0.285,0.221-0.451,0.562-0.451,0.922s0.166,0.701,0.451,0.922l15.413,11.993c0.209,0.163,0.463,0.246,0.718,0.246 c0.175,0,0.35-0.039,0.513-0.119c0.401-0.196,0.655-0.604,0.655-1.05v-5.639h15.526C37.099,48.393,37.622,47.87,37.622,47.225z M35.285,46.056H19.758c-0.645,0-1.169,0.523-1.169,1.169v4.417L6.249,42.039l12.341-9.603v4.417c0,0.645,0.523,1.169,1.169,1.169 h15.526V46.056z"/><text x="0" y="111" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">Created by miftahul huda</text><text x="0" y="116" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">from the Noun Project</text></svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -40,6 +40,7 @@
"better-sqlite3": "^9.3.0",
"cheerio": "1.0.0-rc.12",
"node-fetch": "^3.3.2",
"remeda": "^1.40.1",
"svelte-persisted-store": "^0.9.0",
"vite-multiple-assets": "^1.2.10"
}

View File

@ -40,12 +40,26 @@ games_hidden_store.subscribe((data) =>
localStorage.setItem('games_hidden', JSON.stringify(data)),
);
let cart_store_stored = localStorage.getItem('cart');
if (cart_store_stored) cart_store_stored = JSON.parse(cart_store_stored);
export const cart_store = writable(cart_store_stored || {});
cart_store.subscribe((data) =>
localStorage.setItem('cart', JSON.stringify(data)),
);
export const games_store = derived(
[_games_store, games_hidden_store],
([$games, $hidden]) =>
$games.map((game) => ({ ...game, is_hidden: $hidden[game.id] })),
[_games_store, games_hidden_store, cart_store],
([$games, $hidden, $cart]) =>
$games.map((game) => ({
...game,
is_hidden: $hidden[game.id],
is_in_cart: $cart[game.id],
})),
);
games_store.toggle_hidden = (id) => {
games_hidden_store.update(u.updateIn(id, (v) => !v));
};
games_store.toggle_cart = (id) => {
cart_store.update(u.updateIn(id, (v) => !v));
};

View File

@ -2,7 +2,7 @@
<title>Ottawa board games, trades and sales</title>
</svelte:head>
<main class="responsive">
<AppTop />
<AppTop cart={$cart_store} />
<slot />
</main>
@ -15,9 +15,14 @@
import { persisted } from 'svelte-persisted-store';
import u from '@yanick/updeep-remeda';
import AppTop from './AppTop.svelte';
import { games_store, sellers_store } from '$lib/stores/index.js';
import {
games_store,
sellers_store,
cart_store,
} from '$lib/stores/index.js';
setContext('games', games_store);
setContext('sellers', sellers_store);
setContext('cart', cart_store);
</script>
<style>

View File

@ -12,7 +12,8 @@
games={$games}
sellers={$sellers}
on:toggle_game_visibility={({ detail }) =>
games.toggle_hidden(detail)} />
games.toggle_hidden(detail)}
on:toggle_cart={({ detail }) => games.toggle_cart(detail)} />
{/if}
</article>

View File

@ -5,7 +5,16 @@
on:click={() => (show_menu = !show_menu)}>
<i>menu</i>
</button>
<h5 class="max left-align">Ottawa board games for sale and trade</h5>
<h5 class="max left-align">
<a href="/">Ottawa board games for sale and trade</a>
</h5>
<a class="" href="/cart/">
{#if cart_size}
<span class="badge circle">{cart_size}</span>
{/if}
<i>shopping_cart</i></a>
</nav>
</header>
<dialog
@ -19,6 +28,10 @@
<i>list</i>
<span class="max">listing</span>
</a>
<a href="/cart/" on:click={hide_menu}>
<i>shopping_cart</i>
<span>cart</span>
</a>
<a href="/stats/" on:click={hide_menu}>
<i>numbers</i>
<span>stats</span>
@ -38,6 +51,9 @@
import clickOutside from '$lib/directives/clickOutside.js';
let show_menu = false;
const hide_menu = () => (show_menu = false);
export let cart = [];
$: cart_size = Object.values(cart).filter((x) => x).length;
</script>
<style>

View File

@ -3,20 +3,29 @@
class:hidden={is_hidden}
class="game">
<div class="grid top-align">
<a
class="s12 m2"
target="_blank"
href={`https://boardgamegeek.com/boardgame/${bgg_id}`}>
<img alt="" loading="lazy" src={thumbnail} height="80" /></a>
<div class="s12 m2">
<a
target="_blank"
href={`https://boardgamegeek.com/boardgame/${bgg_id}`}>
<img alt="" loading="lazy" src={thumbnail} height="80" /></a>
</div>
<div class="grid s12 m10">
<div class="s8 left-align">
<strong>
<a
class="game-desc"
target="_blank"
href={`https://boardgamegeek.com/boardgame/${bgg_id}`}>
{name}</a>
</strong>
<div class="max">
{#if is_in_cart}
<i class="star">star</i>
{/if}
<strong>
<a
name={id}
class="game-desc"
target="_blank"
href={`https://boardgamegeek.com/boardgame/${bgg_id}`}>
{name}</a>
</strong>
&nbsp; &nbsp; &nbsp;
<a href={`https://bgg.babyl.ca/#${id}`}><i>link</i></a>
</div>
</div>
<div class="s3">
<div>
@ -39,6 +48,20 @@
</div>
<div class="notes s8">
{notes}
<div class="actions">
<button on:click={toggle_cart}
><i>
{#if is_in_cart}
remove_shopping_cart{:else}
add_shopping_cart
{/if}
</i></button>
<button title="hide game" on:click={toggle_game_visibility}
>{#if is_hidden}<i>visibility_off</i>{:else}
<i>visibility</i>
{/if}
</button>
</div>
</div>
<div class="s3 updated-at">
{#if updated_at}
@ -46,22 +69,17 @@
{/if}
</div>
<div class="s1">
<div>
<button
class="transparent round"
title="hide game"
on:click={toggle_game_visibility}
>{#if is_hidden}<i>visibility_off</i>{:else}
<i>visibility</i>
{/if}
</button>
</div>
<div></div>
</div>
</div>
</div>
</div>
<script>
// TODO show cart icon with badge
// show cart page
// cart store
import { createEventDispatcher } from 'svelte';
import { slide, fade } from 'svelte/transition';
@ -74,6 +92,8 @@
export let price = null;
export let notes = '';
export let updated_at = null;
export let is_in_cart = false;
export let id = '';
function pretty_date(date) {
if (!date) return '';
@ -83,6 +103,7 @@
const dispatch = createEventDispatcher();
const toggle_game_visibility = () => dispatch('toggle_visibility');
const toggle_cart = () => dispatch('toggle_cart');
</script>
<style>
@ -111,4 +132,16 @@
.hidden {
opacity: 60%;
}
.actions {
margin-top: 1em;
display: flex;
justify-content: end;
}
.actions button {
margin: 0.5em 2em 0em 1em;
}
.star {
color: darkorange;
font-size: var(--font-size-12);
}
</style>

View File

@ -21,6 +21,7 @@
{#if show_hidden || !game.is_hidden}
<Game
on:toggle_visibility={() => toggle_visibility(game.id)}
on:toggle_cart={() => toggle_cart(game.id)}
{...game}
seller={sellers[game.username]} />
<div class="medium-divider"></div>
@ -41,6 +42,7 @@
const dispatch = createEventDispatcher();
const toggle_visibility = (id) => dispatch('toggle_game_visibility', id);
const toggle_cart = (id) => dispatch('toggle_cart', id);
// add filter
// add sort (user, game, price)

View File

@ -30,6 +30,14 @@
<p class="send-off">
Enjoy!<br /> <a href="https://boardgamegeek.com/user/yenzie">`/anick</a>
</p>
<p class="copyright">
note: the site's favicon incorporates the Trade by Bombasticon Studio
from <a
href="https://thenounproject.com/browse/icons/term/trade/"
target="_blank"
title="Trade Icons">Noun Project</a> (CC BY 3.0)
</p>
</article>
<script>
@ -58,4 +66,7 @@
margin-right: 1em;
}
}
.copyright {
margin-top: 5em;
}
</style>

View File

@ -0,0 +1,62 @@
<article>
{#if games.length == 0}
<div class="medium-height middle-align center-align">
<div class="center-align">
<h4 class="center-align">Such restraint</h4>
<h5>No games in cart (yet)</h5>
</div>
</div>
{:else}
<GameList
{games}
sellers={$sellers}
on:toggle_cart={({ detail }) => all_games.toggle_cart(detail)} />
{/if}
</article>
<script>
import { getContext } from 'svelte';
import GameList from './GameList.svelte';
const all_games = getContext('games');
const sellers = getContext('sellers');
$: games = $all_games.filter(({ is_in_cart }) => is_in_cart);
</script>
<style>
p {
font-size: var(--font-size-10);
max-width: 60em;
text-align: justify;
margin-left: 3em;
margin-right: 3em;
}
a {
color: var(--primary);
text-decoration: underline;
}
.game-cell {
display: flex;
}
.game-cell > * {
display: block;
}
.game-desc {
flex: 1;
}
td {
font-size: var(--font-size-10);
}
@media screen and (max-width: 730px) {
h1 {
font-size: var(--font-size-12);
}
p {
font-size: inherit;
margin-left: 1em;
margin-right: 1em;
}
}
</style>

113
src/routes/cart/Game.svelte Normal file
View File

@ -0,0 +1,113 @@
<div
transition:slide={{ delay: 250, duration: 300 }}
class:hidden={is_hidden}
class="game">
<div class="grid top-align">
<div class="s12 m2">
<a
target="_blank"
href={`https://boardgamegeek.com/boardgame/${bgg_id}`}>
<img alt="" loading="lazy" src={thumbnail} height="80" /></a>
</div>
<div class="grid s12 m10">
<div class="s8 left-align">
<div class="max">
<strong>
<a
class="game-desc"
target="_blank"
href={`https://boardgamegeek.com/boardgame/${bgg_id}`}>
{name}</a>
</strong>
</div>
</div>
<div class="s3"></div>
<div class="s1 right-align">
{price ? '$' + price : ''}
</div>
<div class="notes s8">
{notes}
</div>
<div class="s3 updated-at">
{#if updated_at}
{pretty_date(updated_at)}
{/if}
</div>
<div class="actions s1">
<button on:click={toggle_cart}
><i>
{#if is_in_cart}
remove_shopping_cart{:else}
add_shopping_cart
{/if}
</i></button>
</div>
</div>
</div>
</div>
<script>
// TODO show cart icon with badge
// show cart page
// cart store
import { createEventDispatcher } from 'svelte';
import { slide, fade } from 'svelte/transition';
export let username = '';
export let name = '';
export let is_hidden = false;
export let bgg_id = '';
export let thumbnail = '';
export let seller = {};
export let price = null;
export let notes = '';
export let updated_at = null;
export let is_in_cart = false;
function pretty_date(date) {
if (!date) return '';
return date.replace(/T.*/, '');
}
const dispatch = createEventDispatcher();
const toggle_game_visibility = () => dispatch('toggle_visibility');
const toggle_cart = () => dispatch('toggle_cart');
</script>
<style>
a {
color: var(--primary);
text-decoration: underline;
}
.grid {
margin-right: 2em;
font-size: var(--font-size-10);
}
.notes {
margin-top: 1em;
margin-left: 1em;
}
.updated-at {
font-size: smaller;
text-align: left;
}
.updated-at::before {
content: 'last update: ';
}
.neighbourhood {
font-size: smaller;
}
.hidden {
opacity: 60%;
}
.actions {
margin-top: 1em;
display: flex;
justify-content: end;
}
.actions button {
margin: 0.5em 2em 0em 1em;
}
</style>

View File

@ -0,0 +1,107 @@
{#each games_sellers as seller}
<h4>
<BggUser username={seller} />
&nbsp;
<a
target="_blank"
href={`https://boardgamegeek.com/geekmail/compose?touser=${seller}`}>
<i>email</i></a>
<span class="neighbourhood">
{sellers[seller]?.neighbourhood ?? ''}
</span>
<span class="nbr-games"
>{games.filter((game) => game.username == seller).length} game(s)</span>
</h4>
<div class="games">
{#each games.filter((game) => {
return game.username == seller;
}) as game}
{#if show_hidden || !game.is_hidden}
<Game
on:toggle_visibility={() => toggle_visibility(game.id)}
on:toggle_cart={() => toggle_cart(game.id)}
{...game}
seller={sellers[game.username]} />
<div class="medium-divider"></div>
{/if}
{/each}
</div>
{/each}
<script>
import { getContext, createEventDispatcher } from 'svelte';
import Game from './Game.svelte';
import BggUser from '$lib/components/BggUser.svelte';
import u from '@yanick/updeep-remeda';
import * as R from 'remeda';
export let games = [];
export let sellers = {};
$: games_sellers = R.uniq(games.map(({ username }) => username).sort());
let show_hidden = false;
let search_text = '';
const dispatch = createEventDispatcher();
const toggle_visibility = (id) => dispatch('toggle_game_visibility', id);
const toggle_cart = (id) => dispatch('toggle_cart', id);
// add filter
// add sort (user, game, price)
</script>
<style>
h4 {
align-items: baseline;
display: flex;
}
.neighbourhood {
margin-left: 2em;
}
.games {
margin-top: 3em;
}
a {
color: var(--primary);
text-decoration: underline;
}
.grid {
margin-right: 2em;
font-size: var(--font-size-10);
}
.notes {
margin-top: 1em;
margin-left: 1em;
}
.updated-at {
font-size: smaller;
text-align: left;
}
.updated-at::before {
content: 'last update: ';
}
.neighbourhood {
font-size: smaller;
}
.hidden {
opacity: 60%;
}
.switch span {
font-size: var(--font-size-10);
padding-left: 1em;
}
.options {
display: flex;
flex-direction: row-reverse;
}
.options > div {
margin-right: 1em;
}
.nbr-games {
font-size: smaller;
flex: 1;
text-align: right;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB