start dev
This commit is contained in:
parent
93cfd87821
commit
144cd4787e
202
package-lock.json
generated
202
package-lock.json
generated
@ -7,6 +7,12 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "fbla26",
|
"name": "fbla26",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
|
"dependencies": {
|
||||||
|
"bcrypt": "^6.0.0",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"jsonwebtoken": "^9.0.3",
|
||||||
|
"postgres": "^3.4.7"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/compat": "^1.4.0",
|
"@eslint/compat": "^1.4.0",
|
||||||
"@eslint/js": "^9.36.0",
|
"@eslint/js": "^9.36.0",
|
||||||
@ -2280,6 +2286,20 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/bcrypt": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-addon-api": "^8.3.0",
|
||||||
|
"node-gyp-build": "^4.8.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
@ -2304,6 +2324,12 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-equal-constant-time": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/cac": {
|
"node_modules/cac": {
|
||||||
"version": "6.7.14",
|
"version": "6.7.14",
|
||||||
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
|
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
|
||||||
@ -2555,6 +2581,27 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
|
"version": "17.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||||
|
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ecdsa-sig-formatter": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.18.3",
|
"version": "5.18.3",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
||||||
@ -3262,6 +3309,49 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonwebtoken": {
|
||||||
|
"version": "9.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
|
||||||
|
"integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jws": "^4.0.1",
|
||||||
|
"lodash.includes": "^4.3.0",
|
||||||
|
"lodash.isboolean": "^3.0.3",
|
||||||
|
"lodash.isinteger": "^4.0.4",
|
||||||
|
"lodash.isnumber": "^3.0.3",
|
||||||
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
"lodash.isstring": "^4.0.1",
|
||||||
|
"lodash.once": "^4.0.0",
|
||||||
|
"ms": "^2.1.1",
|
||||||
|
"semver": "^7.5.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12",
|
||||||
|
"npm": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jwa": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-equal-constant-time": "^1.0.1",
|
||||||
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jws": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jwa": "^2.0.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
@ -3575,6 +3665,42 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.includes": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isboolean": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isinteger": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isnumber": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isstring": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
@ -3582,6 +3708,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.once": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/loupe": {
|
"node_modules/loupe": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
|
||||||
@ -3716,7 +3848,6 @@
|
|||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
@ -3745,6 +3876,26 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/node-addon-api": {
|
||||||
|
"version": "8.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz",
|
||||||
|
"integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || ^20 || >= 21"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp-build": {
|
||||||
|
"version": "4.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||||
|
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"node-gyp-build": "bin.js",
|
||||||
|
"node-gyp-build-optional": "optional.js",
|
||||||
|
"node-gyp-build-test": "build-test.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||||
@ -4041,6 +4192,19 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postgres": {
|
||||||
|
"version": "3.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz",
|
||||||
|
"integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==",
|
||||||
|
"license": "Unlicense",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/porsager"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prelude-ls": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
@ -4366,11 +4530,30 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.7.3",
|
"version": "7.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
@ -5122,21 +5305,6 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
|
||||||
"version": "2.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
|
|
||||||
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
|
||||||
"yaml": "bin.mjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/yocto-queue": {
|
"node_modules/yocto-queue": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
|
|||||||
@ -41,5 +41,11 @@
|
|||||||
"vite": "^7.1.7",
|
"vite": "^7.1.7",
|
||||||
"vitest": "^3.2.4",
|
"vitest": "^3.2.4",
|
||||||
"vitest-browser-svelte": "^1.1.0"
|
"vitest-browser-svelte": "^1.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bcrypt": "^6.0.0",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"jsonwebtoken": "^9.0.3",
|
||||||
|
"postgres": "^3.4.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
315
src/app.css
315
src/app.css
@ -1,2 +1,317 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
@plugin '@tailwindcss/forms';
|
@plugin '@tailwindcss/forms';
|
||||||
|
|
||||||
|
/* defaults */
|
||||||
|
:root {
|
||||||
|
--text-color: #000000;
|
||||||
|
--text-box-bg: #00000010;
|
||||||
|
--bg-color: #e9e9e9;
|
||||||
|
--hover-bg-color: #d0d0d0;
|
||||||
|
--separator-line-color: #a0a0a0;
|
||||||
|
--low-emphasis-text-color: #6b6b6b;
|
||||||
|
--primary-color: #1f96f3;
|
||||||
|
--dull-primary-color: #51aaf0;
|
||||||
|
--elevated-bg-color: #ffffff;
|
||||||
|
--bg-accent-color: #f4f4f4;
|
||||||
|
--danger-color: #ff2d2f;
|
||||||
|
--hyperlink-color: #3b82f6;
|
||||||
|
--nav-bg-color: #f0f0f0;
|
||||||
|
|
||||||
|
background: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-color {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-bg-color:hover {
|
||||||
|
background-color: var(--hover-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.low-emphasis-text {
|
||||||
|
color: var(--low-emphasis-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.low-emphasis-text-button {
|
||||||
|
color: var(--low-emphasis-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.low-emphasis-text-button:hover {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-underline {
|
||||||
|
border-bottom: 2px solid var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-border {
|
||||||
|
border-top: 1px solid var(--separator-line-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-border {
|
||||||
|
border-bottom: 1px solid var(--separator-line-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-border {
|
||||||
|
border-left: 1px solid var(--separator-line-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-border {
|
||||||
|
border-right: 1px solid var(--separator-line-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='search'],
|
||||||
|
input[type='text'],
|
||||||
|
input[type='password'],
|
||||||
|
input[type='email'],
|
||||||
|
input[type='tel'],
|
||||||
|
input[type='number'],
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
@apply rounded-t;
|
||||||
|
background-color: var(--text-box-bg);
|
||||||
|
color: var(--text-color);
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 2px solid var(--separator-line-color);
|
||||||
|
caret-color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='search']:focus,
|
||||||
|
input[type='text']:focus,
|
||||||
|
input[type='password']:focus,
|
||||||
|
input[type='email']:focus,
|
||||||
|
input[type='tel']:focus,
|
||||||
|
input[type='number']:focus,
|
||||||
|
textarea:focus,
|
||||||
|
select:focus {
|
||||||
|
outline: 0 solid var(--text-color);
|
||||||
|
border-bottom: 2px solid var(--primary-color);
|
||||||
|
box-shadow: 0 0 0 0 var(--primary-color);
|
||||||
|
caret-color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='search']:-webkit-autofill,
|
||||||
|
input[type='text']:-webkit-autofill,
|
||||||
|
input[type='password']:-webkit-autofill,
|
||||||
|
input[type='email']:-webkit-autofill,
|
||||||
|
input[type='tel']:-webkit-autofill,
|
||||||
|
input[type='number']:-webkit-autofill,
|
||||||
|
textarea:-webkit-autofill,
|
||||||
|
select:-webkit-autofill {
|
||||||
|
-webkit-text-fill-color: var(--text-color) !important;
|
||||||
|
background-clip: text !important;
|
||||||
|
caret-color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='search'].outlined,
|
||||||
|
input[type='text'].outlined,
|
||||||
|
input[type='password'].outlined,
|
||||||
|
input[type='email'].outlined,
|
||||||
|
input[type='tel'].outlined,
|
||||||
|
input[type='number'].outlined,
|
||||||
|
textarea.outlined,
|
||||||
|
select.outlined {
|
||||||
|
@apply rounded;
|
||||||
|
border: 1px solid var(--separator-line-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='search'].outlined:focus,
|
||||||
|
input[type='text'].outlined:focus,
|
||||||
|
input[type='password'].outlined:focus,
|
||||||
|
input[type='email'].outlined:focus,
|
||||||
|
input[type='tel'].outlined:focus,
|
||||||
|
input[type='number'].outlined:focus,
|
||||||
|
textarea.outlined:focus,
|
||||||
|
select.outlined:focus {
|
||||||
|
border: 1px solid var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='checkbox'] {
|
||||||
|
background-color: var(--text-box-bg);
|
||||||
|
border: 1px solid var(--separator-line-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='checkbox']:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-box-bg {
|
||||||
|
background-color: var(--text-box-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator-borders {
|
||||||
|
border: 1px solid var(--separator-line-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.elevated {
|
||||||
|
background-color: var(--elevated-bg-color);
|
||||||
|
@apply shadow-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.elevated-bg {
|
||||||
|
background-color: var(--elevated-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
@apply rounded-lg p-4 block shadow-lg;
|
||||||
|
background-color: var(--elevated-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-bg {
|
||||||
|
background-color: var(--nav-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-bg-color {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-bg-color {
|
||||||
|
background-color: var(--bg-accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dull-primary-bg-color {
|
||||||
|
background-color: var(--dull-primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dull-primary-text-color {
|
||||||
|
color: var(--dull-primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dull-primary-border-color {
|
||||||
|
border-color: var(--dull-primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-text-color {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger-bg-color {
|
||||||
|
background-color: var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger-color {
|
||||||
|
color: var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger-border-color {
|
||||||
|
border-color: var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-hyperlink:hover {
|
||||||
|
color: var(--hyperlink-color);
|
||||||
|
text-decoration: underline var(--hyperlink-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hyperlink-color {
|
||||||
|
color: var(--hyperlink-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hyperlink-underline {
|
||||||
|
text-decoration: underline var(--hyperlink-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: xx-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.normal, a.normal {
|
||||||
|
@apply px-2 py-1 leading-tight rounded-lg;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: var(--dull-primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.large, a.large {
|
||||||
|
@apply px-4 py-3 leading-tight rounded-xl;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: var(--dull-primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.wide {
|
||||||
|
@apply px-4 py-2 leading-tight rounded w-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.text {
|
||||||
|
color: var(--dull-primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.filled, a.filled {
|
||||||
|
background-color: var(--dull-primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.danger {
|
||||||
|
background-color: var(--danger-color);
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.outlined-danger {
|
||||||
|
border-color: var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.text-danger {
|
||||||
|
color: var(--danger-color);
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
display: flex;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.switch button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border: none;
|
||||||
|
background: #f0f0f0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.switch button.selected {
|
||||||
|
background: #007acc;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: rgb(0, 0, 0); /* Fallback color */
|
||||||
|
background-color: rgba(0, 0, 0, 0.6); /* Darken background */
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
margin: 10% auto;
|
||||||
|
padding: 16px;
|
||||||
|
border: 1px solid var(--separator-line-color);
|
||||||
|
max-width: 420px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:nth-child(even) {
|
||||||
|
background-color: rgb(from var(--primary-color) r g b / 10%);
|
||||||
|
}
|
||||||
|
|||||||
19
src/app.html
19
src/app.html
@ -1,11 +1,14 @@
|
|||||||
|
<!--suppress HtmlUnknownTarget -->
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<title>FBLA26</title>
|
||||||
%sveltekit.head%
|
<link href="%sveltekit.assets%/favicon.png" rel="icon" />
|
||||||
</head>
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<body data-sveltekit-preload-data="hover">
|
%sveltekit.head%
|
||||||
<div style="display: contents">%sveltekit.body%</div>
|
</head>
|
||||||
</body>
|
<body data-sveltekit-preload-data="hover">
|
||||||
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
80
src/lib/auth/index.server.ts
Normal file
80
src/lib/auth/index.server.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import type { User } from '$lib/types';
|
||||||
|
import bcrypt from 'bcrypt';
|
||||||
|
import sql from '$lib/db/db.server';
|
||||||
|
import type { Cookies } from '@sveltejs/kit';
|
||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
|
export function setJWT(cookies: Cookies, user: User) {
|
||||||
|
const payload = {
|
||||||
|
id: user.id,
|
||||||
|
email: user.email,
|
||||||
|
name: user.name
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.env.JWT_SECRET === undefined) {
|
||||||
|
throw new Error('JWT_SECRET not defined');
|
||||||
|
}
|
||||||
|
if (process.env.BASE_URL === undefined) {
|
||||||
|
throw new Error('BASE_URL not defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
const secure: boolean = process.env.BASE_URL?.includes('https://');
|
||||||
|
|
||||||
|
const maxAge = 60 * 60 * 24 * 30; // 30 days
|
||||||
|
const JWT = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '30d' });
|
||||||
|
cookies.set('jwt', JWT, { maxAge, path: '/', httpOnly: false, secure });
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function checkPerms(cookies: Cookies, perms: number): void {
|
||||||
|
// const JWT = cookies.get('jwt');
|
||||||
|
// if (!JWT) throw error(403, 'Unauthorized');
|
||||||
|
// if (process.env.JWT_SECRET === undefined) {
|
||||||
|
// throw new Error('JWT_SECRET not defined');
|
||||||
|
// }
|
||||||
|
// const user = jwt.verify(JWT, process.env.JWT_SECRET) as User;
|
||||||
|
// if ((user.perms & perms) !== perms) {
|
||||||
|
// throw error(403, 'Unauthorized');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// export function hasPerms(cookies: Cookies, perms: number): boolean {
|
||||||
|
// const JWT = cookies.get('jwt');
|
||||||
|
// if (!JWT) return false;
|
||||||
|
// if (process.env.JWT_SECRET === undefined) {
|
||||||
|
// throw new Error('JWT_SECRET not defined');
|
||||||
|
// }
|
||||||
|
// const user = jwt.verify(JWT, process.env.JWT_SECRET) as User;
|
||||||
|
// return (user.perms & perms) === perms;
|
||||||
|
// }
|
||||||
|
|
||||||
|
export async function login(email: string, password: string): Promise<User> {
|
||||||
|
try {
|
||||||
|
const [user] = await sql`
|
||||||
|
SELECT id, email, password_hash, perms, name
|
||||||
|
WHERE email = ${email};
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (await bcrypt.compare(password, user.password_hash)) {
|
||||||
|
delete user.password_hash;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||||
|
sql`
|
||||||
|
UPDATE users
|
||||||
|
SET last_signin = NOW()
|
||||||
|
WHERE id = ${user.id};
|
||||||
|
`;
|
||||||
|
|
||||||
|
return <User>user;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
throw Error('Error signing in ');
|
||||||
|
}
|
||||||
|
throw Error('Invalid email or password');
|
||||||
|
}
|
||||||
|
|
||||||
|
// await createUser(<User>{
|
||||||
|
// email: 'drake@marinodev.com',
|
||||||
|
// password: 'password',
|
||||||
|
// perms: 255,
|
||||||
|
// name: 'Drake'
|
||||||
|
// });
|
||||||
9
src/lib/consts.ts
Normal file
9
src/lib/consts.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const PERMISSIONS = {
|
||||||
|
VIEW: 0b00000001,
|
||||||
|
DO_TASKS: 0b00000010,
|
||||||
|
MANAGE_USERS: 0b00000100,
|
||||||
|
MANAGE_ITEMS: 0b00001000,
|
||||||
|
MANAGE_TASKS: 0b00010000
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EXPIRE_REMINDER_DAYS = 30;
|
||||||
14
src/lib/db/db.server.ts
Normal file
14
src/lib/db/db.server.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import postgres from 'postgres';
|
||||||
|
import * as dotenv from 'dotenv';
|
||||||
|
|
||||||
|
dotenv.config({ path: '.env' });
|
||||||
|
|
||||||
|
const sql = postgres({
|
||||||
|
host: process.env.POSTGRES_HOST,
|
||||||
|
port: parseInt(process.env.POSTGRES_PORT!),
|
||||||
|
database: process.env.POSTGRES_DB,
|
||||||
|
username: process.env.POSTGRES_USER,
|
||||||
|
password: process.env.POSTGRES_PASSWORD
|
||||||
|
});
|
||||||
|
|
||||||
|
export default sql;
|
||||||
67
src/lib/db/users.server.ts
Normal file
67
src/lib/db/users.server.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import type { User } from '$lib/types';
|
||||||
|
import sql from '$lib/db/db.server';
|
||||||
|
import bcrypt from 'bcrypt';
|
||||||
|
|
||||||
|
// should require MANAGE_USERS permission
|
||||||
|
|
||||||
|
export async function getUsers(searchQuery: string | null = null): Promise<User[]> {
|
||||||
|
return sql`
|
||||||
|
SELECT id,
|
||||||
|
email,
|
||||||
|
perms,
|
||||||
|
name,
|
||||||
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
||||||
|
last_signin AT TIME ZONE 'UTC' AS "lastSignIn"
|
||||||
|
FROM users
|
||||||
|
WHERE (${!searchQuery ? sql`TRUE` : sql`email ILIKE ${'%' + searchQuery + '%'} OR name ILIKE ${'%' + searchQuery + '%'}`});
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getUser(id: number): Promise<User> {
|
||||||
|
return <User>(
|
||||||
|
await sql`
|
||||||
|
SELECT id,
|
||||||
|
email,
|
||||||
|
perms,
|
||||||
|
name,
|
||||||
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
||||||
|
last_signin AT TIME ZONE 'UTC' AS "lastSignIn"
|
||||||
|
FROM users
|
||||||
|
WHERE (id = ${id}) LIMIT 1;
|
||||||
|
`
|
||||||
|
)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createUser(user: User) {
|
||||||
|
const passwordHash = await bcrypt.hash(user.password!, 12);
|
||||||
|
await sql`
|
||||||
|
INSERT INTO users (email, password_hash, perms, name, created_at, last_signin)
|
||||||
|
VALUES (${user.email}, ${passwordHash}, ${user.perms}, ${user.name}, NOW(), NOW())
|
||||||
|
RETURNING id;
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editUser(user: User) {
|
||||||
|
let passwordHash: string | undefined;
|
||||||
|
if (user.password) {
|
||||||
|
passwordHash = await bcrypt.hash(user.password, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
await sql`
|
||||||
|
UPDATE users
|
||||||
|
SET
|
||||||
|
email = ${user.email},
|
||||||
|
${passwordHash ? sql`password_hash = ${passwordHash},` : sql``}
|
||||||
|
perms = ${user.perms},
|
||||||
|
name = ${user.name}
|
||||||
|
WHERE id = ${user.id!}
|
||||||
|
RETURNING id;
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteUser(id: number) {
|
||||||
|
await sql`
|
||||||
|
DELETE FROM users
|
||||||
|
WHERE id = ${id}
|
||||||
|
`;
|
||||||
|
}
|
||||||
21
src/lib/types.ts
Normal file
21
src/lib/types.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export interface User {
|
||||||
|
id: number;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
password?: string;
|
||||||
|
name: string;
|
||||||
|
createdAt: Date;
|
||||||
|
lastSignIn: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Item {
|
||||||
|
id: number;
|
||||||
|
ownerEmail: string;
|
||||||
|
ownerPhone: string;
|
||||||
|
foundDate: Date;
|
||||||
|
approvedDate?: Date;
|
||||||
|
claimedDate?: Date;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
transferred: boolean; // to L&F location
|
||||||
|
}
|
||||||
41
src/lib/utils.ts
Normal file
41
src/lib/utils.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import type { User } from '$lib/types';
|
||||||
|
|
||||||
|
export const getCookieValue = (name: string): string =>
|
||||||
|
document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || '';
|
||||||
|
|
||||||
|
export const getUserFromJWT = (jwt: string): User => JSON.parse(atob(jwt.split('.')[1]));
|
||||||
|
|
||||||
|
// export const userData = () => {
|
||||||
|
// let userData: User | null = null;
|
||||||
|
// const cookieValue = getCookieValue('jwt');
|
||||||
|
// if (cookieValue) {
|
||||||
|
// userData = getUserFromJWT(cookieValue);
|
||||||
|
// }
|
||||||
|
// return userData;
|
||||||
|
// };
|
||||||
|
|
||||||
|
export function getFormString(data: FormData, key: string): string | undefined {
|
||||||
|
const value = data.get(key);
|
||||||
|
if (value === null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
throw Error(`Incorrect input in field ${key}.`);
|
||||||
|
}
|
||||||
|
return value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRequiredFormString(data: FormData, key: string) {
|
||||||
|
const value = data.get(key);
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
throw Error(`Missing required field ${key}.`);
|
||||||
|
}
|
||||||
|
return value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dateFormatOptions: Intl.DateTimeFormatOptions = {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric'
|
||||||
|
};
|
||||||
10
src/routes/+layout.server.ts
Normal file
10
src/routes/+layout.server.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import type { LayoutServerLoad } from './$types';
|
||||||
|
import { getUserFromJWT } from '$lib/utils';
|
||||||
|
|
||||||
|
export const load: LayoutServerLoad = ({ cookies }) => {
|
||||||
|
const jwt = cookies.get('jwt');
|
||||||
|
if (jwt) {
|
||||||
|
return { selfUser: getUserFromJWT(jwt) };
|
||||||
|
}
|
||||||
|
return { selfUser: null };
|
||||||
|
};
|
||||||
@ -1,12 +1,29 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.css';
|
import '../app.css';
|
||||||
import favicon from '$lib/assets/favicon.svg';
|
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<link
|
||||||
<link rel="icon" href={favicon} />
|
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..40,400,0,0&display=block&icon_names=account_circle,arrow_drop_down,arrow_drop_up,calendar_today,call,check,close,cloud_upload,dark_mode,delete,description,edit,group,home,info,light_mode,login,mail,menu,open_in_new,person,search,sell,store,upload,visibility,visibility_off,work"
|
||||||
</svelte:head>
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
|
||||||
{@render children?.()}
|
<!--<header class="bottom-border flex justify-between">-->
|
||||||
|
<!-- <a class="material-symbols-outlined p-2 !text-3xl leading-none" href="/">home</a>-->
|
||||||
|
<!-- {#if data.selfUser}-->
|
||||||
|
<!-- <a class="material-symbols-outlined p-2 !text-3xl leading-none" href="/account"-->
|
||||||
|
<!-- >account_circle</a-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- {:else}-->
|
||||||
|
<!-- <a class="material-symbols-outlined p-2 !text-3xl leading-none" href="/signin">login</a>-->
|
||||||
|
<!-- {/if}-->
|
||||||
|
<!--</header>-->
|
||||||
|
|
||||||
|
<div style="max-width: 800px;" class="center">
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
|
||||||
|
</footer>
|
||||||
|
|||||||
@ -1,2 +1,6 @@
|
|||||||
<h1>Welcome to SvelteKit</h1>
|
<h1>Welcome to SvelteKit</h1>
|
||||||
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
|
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
0
src/routes/signin/+page.server.ts
Normal file
0
src/routes/signin/+page.server.ts
Normal file
0
src/routes/signin/+page.svelte
Normal file
0
src/routes/signin/+page.svelte
Normal file
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
50
static/mdevtriangle.svg
Normal file
50
static/mdevtriangle.svg
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="80mm"
|
||||||
|
height="80mm"
|
||||||
|
viewBox="0 0 80 80"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||||
|
sodipodi:docname="triangleblue.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="2"
|
||||||
|
inkscape:cx="81"
|
||||||
|
inkscape:cy="106.5"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1046"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
shape-rendering="crispEdges"
|
||||||
|
inkscape:export-bgcolor="#ffffffff" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
d="m 40.063302,5.1541583 c -1.24713,0 -2.07854,1.440059 -2.07854,1.440059 l -4.57281,7.9203207 17.81611,30.858401 c 4.37185,-0.996148 6.86321,4.803857 3.14145,7.293026 -3.72178,2.489169 -8.13084,-2.028265 -5.54068,-5.688379 v 0 L 31.749122,17.394653 0.57092766,71.396858 c -0.554314,0.96004 -0.623535,1.80008 -0.207839,2.52011 0.41568997,0.72005 1.17784894,1.08004 2.28640594,1.08004 H 11.795099 L 29.611202,44.138609 c -3.04862,-3.288058 0.72867,-8.345647 4.74522,-6.367078 4.01656,1.97857 2.30888,8.055642 -2.15596,7.642556 v 0 L 15.120758,74.997008 h 62.356384 c 0,0 1.66283,0 2.2864,-1.08004 0.62353,-1.08005 -0.20784,-2.52011 -0.20784,-2.52011 l -4.57281,-7.92032 h -35.63222 c -1.32322,4.28422 -7.59186,3.5418 -7.88666,-0.92594 -0.29484,-4.467728 5.82195,-6.027375 7.69662,-1.95418 v 0 h 34.15941 L 42.141852,6.5942173 c 0,0 -0.83138,-1.440059 -2.07855,-1.440059"
|
||||||
|
style="display:inline;fill:#2096f3;fill-opacity:1;stroke:none;stroke-width:2.37548"
|
||||||
|
id="path395"
|
||||||
|
inkscape:label="triangle"
|
||||||
|
inkscape:transform-center-y="-11.666667" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
BIN
static/sdwLogo.png
Normal file
BIN
static/sdwLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
Loading…
Reference in New Issue
Block a user