feat: openapi-fetch typing

feat: base page layout for implementation

todo: fix light/dark mode toggling
This commit is contained in:
2025-08-10 10:50:52 +01:00
parent ce03e2f681
commit 53ea5021d7
10 changed files with 2010 additions and 13 deletions

1
web/.env.example Normal file
View File

@@ -0,0 +1 @@
PUBLIC_API_URL=http://localhost:80/

View File

@@ -11,7 +11,8 @@
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"format": "prettier --write .",
"lint": "prettier --check . && eslint ."
"lint": "prettier --check . && eslint .",
"gen-openapi": "openapi-typescript ../schema/openapi/openapi.yaml -o ./src/lib/api/schema.d.ts"
},
"devDependencies": {
"@eslint/compat": "^1.2.5",
@@ -29,6 +30,7 @@
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-svelte": "^3.0.0",
"globals": "^16.0.0",
"openapi-typescript": "^7.8.0",
"prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11",
@@ -43,5 +45,8 @@
"onlyBuiltDependencies": [
"esbuild"
]
},
"dependencies": {
"openapi-fetch": "^0.14.0"
}
}

219
web/pnpm-lock.yaml generated
View File

@@ -7,6 +7,10 @@ settings:
importers:
.:
dependencies:
openapi-fetch:
specifier: ^0.14.0
version: 0.14.0
devDependencies:
'@eslint/compat':
specifier: ^1.2.5
@@ -53,6 +57,9 @@ importers:
globals:
specifier: ^16.0.0
version: 16.3.0
openapi-typescript:
specifier: ^7.8.0
version: 7.8.0(typescript@5.9.2)
prettier:
specifier: ^3.4.2
version: 3.6.2
@@ -87,6 +94,14 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@7.27.1':
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
engines: {node: '>=6.9.0'}
'@esbuild/aix-ppc64@0.25.8':
resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==}
engines: {node: '>=18'}
@@ -351,6 +366,16 @@ packages:
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
'@redocly/ajv@8.11.3':
resolution: {integrity: sha512-4P3iZse91TkBiY+Dx5DUgxQ9GXkVJf++cmI0MOyLDxV9b5MUBI4II6ES8zA5JCbO72nKAJxWrw4PUPW+YP3ZDQ==}
'@redocly/config@0.22.2':
resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==}
'@redocly/openapi-core@1.34.5':
resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==}
engines: {node: '>=18.17.0', npm: '>=9.5.0'}
'@rollup/plugin-commonjs@28.0.6':
resolution: {integrity: sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==}
engines: {node: '>=16.0.0 || 14 >= 14.17'}
@@ -827,9 +852,17 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
agent-base@7.1.4:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'}
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
ansi-colors@4.1.3:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
engines: {node: '>=6'}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
@@ -866,6 +899,9 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
change-case@5.4.4:
resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==}
chokidar@4.0.3:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'}
@@ -885,6 +921,9 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
colorette@1.4.0:
resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==}
commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
@@ -1091,6 +1130,10 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
https-proxy-agent@7.0.6:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -1107,6 +1150,10 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
index-to-position@1.1.0:
resolution: {integrity: sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==}
engines: {node: '>=18'}
is-core-module@2.16.1:
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
engines: {node: '>= 0.4'}
@@ -1139,6 +1186,13 @@ packages:
resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==}
hasBin: true
js-levenshtein@1.1.6:
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
engines: {node: '>=0.10.0'}
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@@ -1149,6 +1203,9 @@ packages:
json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
@@ -1264,6 +1321,10 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@5.1.6:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
engines: {node: '>=10'}
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
@@ -1300,6 +1361,18 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
openapi-fetch@0.14.0:
resolution: {integrity: sha512-PshIdm1NgdLvb05zp8LqRQMNSKzIlPkyMxYFxwyHR+UlKD4t2nUjkDhNxeRbhRSEd3x5EUNh2w5sJYwkhOH4fg==}
openapi-typescript-helpers@0.0.15:
resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==}
openapi-typescript@7.8.0:
resolution: {integrity: sha512-1EeVWmDzi16A+siQlo/SwSGIT7HwaFAVjvMA7/jG5HMLSnrUOzPL7uSTRZZa4v/LCRxHTApHKtNY6glApEoiUQ==}
hasBin: true
peerDependencies:
typescript: ^5.x
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@@ -1316,6 +1389,10 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
parse-json@8.3.0:
resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==}
engines: {node: '>=18'}
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -1338,6 +1415,10 @@ packages:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'}
pluralize@8.0.0:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
postcss-load-config@3.1.4:
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
engines: {node: '>= 10'}
@@ -1464,6 +1545,10 @@ packages:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -1517,6 +1602,10 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
supports-color@10.1.0:
resolution: {integrity: sha512-GBuewsPrhJPftT+fqDa9oI/zc5HNsG9nREqwzoSFDOIqf0NggOZbHQj2TE1P1CDJK8ZogFnlZY9hWoUiur7I/A==}
engines: {node: '>=18'}
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@@ -1579,6 +1668,10 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
type-fest@4.41.0:
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
engines: {node: '>=16'}
typescript-eslint@8.39.0:
resolution: {integrity: sha512-lH8FvtdtzcHJCkMOKnN73LIn6SLTpoojgJqDAxPm1jCR14eWSGPX8ul/gggBdPMk/d5+u9V854vTYQ8T5jF/1Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1591,6 +1684,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
uri-js-replace@1.0.1:
resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==}
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@@ -1658,10 +1754,17 @@ packages:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
yaml-ast-parser@0.0.43:
resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==}
yaml@1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
@@ -1676,6 +1779,14 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.12
'@jridgewell/trace-mapping': 0.3.29
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.27.1
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/helper-validator-identifier@7.27.1': {}
'@esbuild/aix-ppc64@0.25.8':
optional: true
@@ -1768,7 +1879,7 @@ snapshots:
'@eslint/config-array@0.21.0':
dependencies:
'@eslint/object-schema': 2.1.6
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
@@ -1782,7 +1893,7 @@ snapshots:
'@eslint/eslintrc@3.3.1':
dependencies:
ajv: 6.12.6
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
espree: 10.4.0
globals: 14.0.0
ignore: 5.3.2
@@ -1858,6 +1969,29 @@ snapshots:
'@polka/url@1.0.0-next.29': {}
'@redocly/ajv@8.11.3':
dependencies:
fast-deep-equal: 3.1.3
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
uri-js-replace: 1.0.1
'@redocly/config@0.22.2': {}
'@redocly/openapi-core@1.34.5(supports-color@10.1.0)':
dependencies:
'@redocly/ajv': 8.11.3
'@redocly/config': 0.22.2
colorette: 1.4.0
https-proxy-agent: 7.0.6(supports-color@10.1.0)
js-levenshtein: 1.1.6
js-yaml: 4.1.0
minimatch: 5.1.6
pluralize: 8.0.0
yaml-ast-parser: 0.0.43
transitivePeerDependencies:
- supports-color
'@rollup/plugin-commonjs@28.0.6(rollup@4.46.2)':
dependencies:
'@rollup/pluginutils': 5.2.0(rollup@4.46.2)
@@ -2023,7 +2157,7 @@ snapshots:
'@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1))':
dependencies:
'@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1))
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
svelte: 5.38.0
vite: 7.0.6(jiti@2.5.1)(lightningcss@1.30.1)
transitivePeerDependencies:
@@ -2032,7 +2166,7 @@ snapshots:
'@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1))':
dependencies:
'@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1))
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.17
@@ -2152,7 +2286,7 @@ snapshots:
'@typescript-eslint/types': 8.39.0
'@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2)
'@typescript-eslint/visitor-keys': 8.39.0
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
eslint: 9.32.0(jiti@2.5.1)
typescript: 5.9.2
transitivePeerDependencies:
@@ -2162,7 +2296,7 @@ snapshots:
dependencies:
'@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2)
'@typescript-eslint/types': 8.39.0
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
typescript: 5.9.2
transitivePeerDependencies:
- supports-color
@@ -2181,7 +2315,7 @@ snapshots:
'@typescript-eslint/types': 8.39.0
'@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2)
'@typescript-eslint/utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
eslint: 9.32.0(jiti@2.5.1)
ts-api-utils: 2.1.0(typescript@5.9.2)
typescript: 5.9.2
@@ -2196,7 +2330,7 @@ snapshots:
'@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2)
'@typescript-eslint/types': 8.39.0
'@typescript-eslint/visitor-keys': 8.39.0
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.5
@@ -2457,6 +2591,8 @@ snapshots:
acorn@8.15.0: {}
agent-base@7.1.4: {}
ajv@6.12.6:
dependencies:
fast-deep-equal: 3.1.3
@@ -2464,6 +2600,8 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
ansi-colors@4.1.3: {}
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
@@ -2496,6 +2634,8 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
change-case@5.4.4: {}
chokidar@4.0.3:
dependencies:
readdirp: 4.1.2
@@ -2510,6 +2650,8 @@ snapshots:
color-name@1.1.4: {}
colorette@1.4.0: {}
commondir@1.0.1: {}
concat-map@0.0.1: {}
@@ -2526,9 +2668,11 @@ snapshots:
csstype@3.1.3: {}
debug@4.4.1:
debug@4.4.1(supports-color@10.1.0):
dependencies:
ms: 2.1.3
optionalDependencies:
supports-color: 10.1.0
deep-is@0.1.4: {}
@@ -2623,7 +2767,7 @@ snapshots:
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.6
debug: 4.4.1
debug: 4.4.1(supports-color@10.1.0)
escape-string-regexp: 4.0.0
eslint-scope: 8.4.0
eslint-visitor-keys: 4.2.1
@@ -2742,6 +2886,13 @@ snapshots:
dependencies:
function-bind: 1.1.2
https-proxy-agent@7.0.6(supports-color@10.1.0):
dependencies:
agent-base: 7.1.4
debug: 4.4.1(supports-color@10.1.0)
transitivePeerDependencies:
- supports-color
ignore@5.3.2: {}
ignore@7.0.5: {}
@@ -2753,6 +2904,8 @@ snapshots:
imurmurhash@0.1.4: {}
index-to-position@1.1.0: {}
is-core-module@2.16.1:
dependencies:
hasown: 2.0.2
@@ -2779,6 +2932,10 @@ snapshots:
jiti@2.5.1: {}
js-levenshtein@1.1.6: {}
js-tokens@4.0.0: {}
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
@@ -2787,6 +2944,8 @@ snapshots:
json-schema-traverse@0.4.1: {}
json-schema-traverse@1.0.0: {}
json-stable-stringify-without-jsonify@1.0.1: {}
keyv@4.5.4:
@@ -2876,6 +3035,10 @@ snapshots:
dependencies:
brace-expansion: 1.1.12
minimatch@5.1.6:
dependencies:
brace-expansion: 2.0.2
minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.2
@@ -2898,6 +3061,22 @@ snapshots:
natural-compare@1.4.0: {}
openapi-fetch@0.14.0:
dependencies:
openapi-typescript-helpers: 0.0.15
openapi-typescript-helpers@0.0.15: {}
openapi-typescript@7.8.0(typescript@5.9.2):
dependencies:
'@redocly/openapi-core': 1.34.5(supports-color@10.1.0)
ansi-colors: 4.1.3
change-case: 5.4.4
parse-json: 8.3.0
supports-color: 10.1.0
typescript: 5.9.2
yargs-parser: 21.1.1
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -2919,6 +3098,12 @@ snapshots:
dependencies:
callsites: 3.1.0
parse-json@8.3.0:
dependencies:
'@babel/code-frame': 7.27.1
index-to-position: 1.1.0
type-fest: 4.41.0
path-exists@4.0.0: {}
path-key@3.1.1: {}
@@ -2931,6 +3116,8 @@ snapshots:
picomatch@4.0.3: {}
pluralize@8.0.0: {}
postcss-load-config@3.1.4(postcss@8.5.6):
dependencies:
lilconfig: 2.1.0
@@ -2985,6 +3172,8 @@ snapshots:
readdirp@4.1.2: {}
require-from-string@2.0.2: {}
resolve-from@4.0.0: {}
resolve@1.22.10:
@@ -3049,6 +3238,8 @@ snapshots:
strip-json-comments@3.1.1: {}
supports-color@10.1.0: {}
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
@@ -3127,6 +3318,8 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
type-fest@4.41.0: {}
typescript-eslint@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2):
dependencies:
'@typescript-eslint/eslint-plugin': 8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)
@@ -3140,6 +3333,8 @@ snapshots:
typescript@5.9.2: {}
uri-js-replace@1.0.1: {}
uri-js@4.4.1:
dependencies:
punycode: 2.3.1
@@ -3171,8 +3366,12 @@ snapshots:
yallist@5.0.0: {}
yaml-ast-parser@0.0.43: {}
yaml@1.10.2: {}
yargs-parser@21.1.1: {}
yocto-queue@0.1.0: {}
zimmerframe@1.1.2: {}

View File

@@ -0,0 +1,10 @@
<script lang="ts">
import LightDarkMode from './LightDarkMode.svelte';
</script>
<footer class="border-t border-surface-300-600 bg-surface-100-800">
<div class="mx-auto flex w-full max-w-7xl items-center justify-between px-4 py-6 text-sm text-surface-700-300">
<span>Stocklet</span>
<LightDarkMode />
</div>
</footer>

View File

@@ -0,0 +1,26 @@
<script lang="ts">
import { Switch } from '@skeletonlabs/skeleton-svelte';
let checked = $state(false);
$effect(() => {
const mode = localStorage.getItem('mode') || 'light';
checked = mode === 'dark';
});
const onCheckedChange = (event: { checked: boolean }) => {
const mode = event.checked ? 'dark' : 'light';
document.documentElement.setAttribute('data-mode', mode);
localStorage.setItem('mode', mode);
checked = event.checked;
};
</script>
<svelte:head>
<script>
const mode = localStorage.getItem('mode') || 'light';
document.documentElement.setAttribute('data-mode', mode);
</script>
</svelte:head>
<Switch {checked} {onCheckedChange}></Switch>

View File

@@ -0,0 +1,8 @@
import createClient from "openapi-fetch";
import type { paths } from "./schema.d";
import { API_URL } from "../config";
const client = createClient<paths>({ baseUrl: API_URL });
export default client;

1614
web/src/lib/api/schema.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

3
web/src/lib/config.ts Normal file
View File

@@ -0,0 +1,3 @@
import { PUBLIC_API_URL } from "$env/static/public";
export const API_URL = PUBLIC_API_URL || "http://localhost:80/v1/";

View File

@@ -1,2 +1,98 @@
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
<script lang="ts">
import { Navigation, Avatar, Rating } from '@skeletonlabs/skeleton-svelte';
import Footer from '../components/Footer.svelte';
</script>
<div data-theme="theme" class="min-h-screen flex flex-col">
<!-- Navbar -->
<header class="border-b border-surface-200-800 bg-surface-100-900">
<div class="mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 items-center justify-between">
<a href="/" class="flex items-center gap-2 font-semibold">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="h-6 w-6 text-primary-500"><path d="M3 3h18v2H3zM3 7h18v2H3zM3 11h18v2H3zM3 15h18v2H3zM3 19h18v2H3z"/></svg>
<span>Stocklet</span>
</a>
<Navigation.Bar classes="bg-transparent width-auto h-12 p-0">
<Navigation.Tile href="/" label="Home" />
<Navigation.Tile href="#" label="Products" />
<Navigation.Tile href="#" label="Orders" />
<Navigation.Tile href="#" label="Account" />
</Navigation.Bar>
</div>
</div>
</header>
<!-- Hero -->
<section class="relative overflow-hidden bg-surface-50-950">
<div class="mx-auto max-w-7xl px-4 py-20 sm:px-6 lg:px-8">
<div class="grid items-center gap-12 md:grid-cols-2">
<div>
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl md:text-6xl">
Phasellus ut pulvinar nisl.
</h1>
<p class="mt-6 max-w-prose text-lg opacity-80">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer dignissim odio orci, in volutpat nunc lacinia et. Phasellus ut dictum nibh. Donec hendrerit nunc sed elit porttitor, in efficitur arcu hendrerit.
Aenean erat est, maximus id congue ut, venenatis eu nibh. Vivamus vitae varius erat, eu tempor urna. Aenean viverra sed erat sed viverra. Fusce vulputate, mauris eget hendrerit venenatis, eros felis rutrum orci, in commodo mauris elit sit amet arcu.
</p>
<div class="mt-8 flex flex-wrap items-center gap-3">
<a href="#get-started" class="rounded-container preset-filled-primary-500 px-5 py-3 text-sm">Start browsing</a>
<a href="/docs" class="rounded-container border border-surface-300-700 px-5 py-3 text-sm hover:bg-surface-100-900">Check orders</a>
</div>
</div>
<div class="relative">
<div class="aspect-[4/3] w-full overflow-hidden rounded-container border border-surface-200-800 bg-surface-50-950 shadow-sm">
<div class="h-full w-full opacity-70" style="background: conic-gradient(at 20% 20%, var(--color-primary-50), transparent, var(--color-primary-50));"></div>
</div>
<div class="pointer-events-none absolute -right-10 -top-10 h-40 w-40 rounded-full preset-filled-secondary-500 blur-2xl opacity-20"></div>
</div>
</div>
</div>
</section>
<!-- Testimonials -->
<section id="testimonials" class="bg-surface-50-950">
<div class="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:px-8">
<h2 class="text-center text-3xl font-bold tracking-tight sm:text-4xl">Loved by providers</h2>
<p class="mx-auto mt-3 max-w-2xl text-center opacity-80">
Providers use Stocklet to sell their products with confidence.
</p>
<div class="mt-10 grid gap-6 md:grid-cols-2 lg:grid-cols-3">
<figure class="rounded-container border border-surface-200-800 bg-surface-50-950 p-6 shadow-sm">
<blockquote>“Vivamus sit amet est eu urna lobortis cursus sed at odio.”</blockquote>
<figcaption class="mt-4 flex items-center gap-3 text-sm opacity-70">
<Avatar name="John Doe" classes="h-8 w-8" />
<div>
<div class="font-medium">John Doe</div>
<div>CEO, Acme Inc.</div>
</div>
<Rating value={5} readOnly controlGap="gap-1" />
</figcaption>
</figure>
<figure class="rounded-container border border-surface-200-800 bg-surface-50-950 p-6 shadow-sm">
<blockquote>“Aliquam velit augue, varius quis est ac, interdum tincidunt lorem.”</blockquote>
<figcaption class="mt-4 flex items-center gap-3 text-sm opacity-70">
<Avatar name="Jane Doe" classes="h-8 w-8" />
<div>
<div class="font-medium">Jane Doe</div>
<div>Product Lead, Wayne Industries.</div>
</div>
<Rating value={5} readOnly controlGap="gap-1" />
</figcaption>
</figure>
<figure class="rounded-container border border-surface-200-800 bg-surface-50-950 p-6 shadow-sm">
<blockquote>“Aliquam a lobortis nisi. Nullam varius a diam nec vulputate.”</blockquote>
<figcaption class="mt-4 flex items-center gap-3 text-sm opacity-70">
<Avatar name="Alice Wonderland" classes="h-8 w-8" />
<div>
<div class="font-medium">Alice Wonderland</div>
<div>Managing Directory, E Corp.</div>
</div>
<Rating value={5} readOnly controlGap="gap-1" />
</figcaption>
</figure>
</div>
</div>
</section>
<Footer />
</div>

35
web/src/stores/theme.ts Normal file
View File

@@ -0,0 +1,35 @@
import { writable } from 'svelte/store';
function getInitialDark(): boolean {
if (typeof window === 'undefined') return false;
try {
const saved = localStorage.getItem('color-scheme');
if (saved === 'dark') return true;
if (saved === 'light') return false;
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
} catch {
return false;
}
}
export const darkMode = writable<boolean>(getInitialDark());
export function setDarkMode(value: boolean): void {
darkMode.set(value);
}
export function toggleDarkMode(): void {
darkMode.update((v) => !v);
}
if (typeof window !== 'undefined') {
darkMode.subscribe((isDark) => {
const root = document.documentElement;
root.classList.toggle('dark', isDark);
try {
localStorage.setItem('color-scheme', isDark ? 'dark' : 'light');
} catch {
// ignore storage write errors
}
});
}