Compare commits
4 Commits
52c3b9c871
...
supabase
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a38edfbc07 | ||
|
|
6c2e80ecc1 | ||
|
|
c28c338de4 | ||
|
|
906f0376d2 |
@@ -46,7 +46,7 @@ jobs:
|
|||||||
org.opencontainers.image.revision=${{ env.GITHUB_SHA }}
|
org.opencontainers.image.revision=${{ env.GITHUB_SHA }}
|
||||||
org.opencontainers.image.vendor=Orebolt.cz
|
org.opencontainers.image.vendor=Orebolt.cz
|
||||||
org.opencontainers.image.ref.name=${{ env.GITHUB_REF }}
|
org.opencontainers.image.ref.name=${{ env.GITHUB_REF }}
|
||||||
org.opencontainers.image.title=ESN Code Scanner App
|
org.opencontainers.image.title=ScanWave
|
||||||
|
|
||||||
- name: Run Trivy vulnerability scanner
|
- name: Run Trivy vulnerability scanner
|
||||||
uses: aquasecurity/trivy-action@0.24.0
|
uses: aquasecurity/trivy-action@0.24.0
|
||||||
|
|||||||
12
docker-compose-prod.yml
Normal file
12
docker-compose-prod.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: ${DOCKER_REGISTRY}/${DOCKER_USER}/${DOCKER_IMAGE}:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file: .env
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.scan-wave.rule=Host(`scanwave.orebolt.cz`)"
|
||||||
|
- "traefik.http.routers.scan-wave.tls.certresolver=leresolver"
|
||||||
|
- "traefik.http.routers.scan-wave.entrypoints=websecure"
|
||||||
|
- "traefik.http.services.scan-wave.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.http.routers.scan-wave.middlewares=hsts"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
image: ${DOCKER_REGISTRY}/${DOCKER_USER}/esn-code-scanner-app:latest
|
image: ${DOCKER_REGISTRY}/${DOCKER_USER}/${DOCKER_IAMGE}:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
93
package-lock.json
generated
93
package-lock.json
generated
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "esn-code-scanner",
|
"name": "scan-wave",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "esn-code-scanner",
|
"name": "scan-wave",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@supabase/ssr": "^0.6.1",
|
"@supabase/ssr": "^0.6.1",
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"simple-icons": "^15.3.0"
|
"simple-icons": "^15.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/kit": "^2.16.0",
|
"@sveltejs/kit": "^2.22.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
"@tailwindcss/vite": "^4.0.0",
|
"@tailwindcss/vite": "^4.0.0",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"svelte-check": "^4.0.0",
|
"svelte-check": "^4.0.0",
|
||||||
"tailwindcss": "^4.0.0",
|
"tailwindcss": "^4.0.0",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^6.2.6"
|
"vite-plugin-devtools-json": "^0.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"aix"
|
"aix"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -74,6 +75,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -90,6 +92,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -106,6 +109,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -122,6 +126,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -138,6 +143,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -154,6 +160,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -170,6 +177,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -186,6 +194,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -202,6 +211,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -218,6 +228,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -234,6 +245,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -250,6 +262,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -266,6 +279,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -282,6 +296,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -298,6 +313,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -314,6 +330,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -330,6 +347,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"netbsd"
|
"netbsd"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -346,6 +364,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"netbsd"
|
"netbsd"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -362,6 +381,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"openbsd"
|
"openbsd"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -378,6 +398,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"openbsd"
|
"openbsd"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -394,6 +415,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"sunos"
|
"sunos"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -410,6 +432,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -426,6 +449,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -442,6 +466,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -994,15 +1019,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sveltejs/kit": {
|
"node_modules/@sveltejs/kit": {
|
||||||
"version": "2.21.0",
|
"version": "2.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.22.0.tgz",
|
||||||
"integrity": "sha512-kvu4h9qXduiPk1Q1oqFKDLFGu/7mslEYbVaqpbBcBxjlRJnvNCFwEvEwKt0Mx9TtSi8J77xRelvJobrGlst4nQ==",
|
"integrity": "sha512-DJm0UxVgzXq+1MUfiJK4Ridk7oIQsIets6JwHiEl97sI6nXScfXe+BeqNhzB7jQIVBb3BM51U4hNk8qQxRXBAA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/acorn-typescript": "^1.0.5",
|
"@sveltejs/acorn-typescript": "^1.0.5",
|
||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
"acorn": "^8.14.1",
|
"acorn": "^8.14.1",
|
||||||
"cookie": "^0.7.0",
|
"cookie": "^0.6.0",
|
||||||
"devalue": "^5.1.0",
|
"devalue": "^5.1.0",
|
||||||
"esm-env": "^1.2.2",
|
"esm-env": "^1.2.2",
|
||||||
"kleur": "^4.1.5",
|
"kleur": "^4.1.5",
|
||||||
@@ -1010,7 +1035,8 @@
|
|||||||
"mrmime": "^2.0.0",
|
"mrmime": "^2.0.0",
|
||||||
"sade": "^1.8.1",
|
"sade": "^1.8.1",
|
||||||
"set-cookie-parser": "^2.6.0",
|
"set-cookie-parser": "^2.6.0",
|
||||||
"sirv": "^3.0.0"
|
"sirv": "^3.0.0",
|
||||||
|
"vitefu": "^1.0.6"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"svelte-kit": "svelte-kit.js"
|
"svelte-kit": "svelte-kit.js"
|
||||||
@@ -1019,9 +1045,9 @@
|
|||||||
"node": ">=18.13"
|
"node": ">=18.13"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0",
|
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0",
|
||||||
"svelte": "^4.0.0 || ^5.0.0-next.0",
|
"svelte": "^4.0.0 || ^5.0.0-next.0",
|
||||||
"vite": "^5.0.3 || ^6.0.0"
|
"vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sveltejs/vite-plugin-svelte": {
|
"node_modules/@sveltejs/vite-plugin-svelte": {
|
||||||
@@ -1604,9 +1630,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/cookie": {
|
"node_modules/cookie": {
|
||||||
"version": "0.7.2",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
@@ -1770,6 +1796,7 @@
|
|||||||
"integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==",
|
"integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"esbuild": "bin/esbuild"
|
"esbuild": "bin/esbuild"
|
||||||
},
|
},
|
||||||
@@ -2570,6 +2597,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"nanoid": "bin/nanoid.cjs"
|
"nanoid": "bin/nanoid.cjs"
|
||||||
},
|
},
|
||||||
@@ -2730,6 +2758,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.8",
|
"nanoid": "^3.3.8",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -3236,6 +3265,13 @@
|
|||||||
"typescript": ">=5.0.0"
|
"typescript": ">=5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svelte-kit": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-kit/-/svelte-kit-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-RRaOHBhpDv4g2v9tcq8iNw055Pt0MlLps6JVA7/40f4KAbtztXSI4T6MZYbHRirO708urfAAMx6Qow+tQfCHug==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz",
|
||||||
@@ -3276,6 +3312,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
|
||||||
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
|
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fdir": "^6.4.4",
|
"fdir": "^6.4.4",
|
||||||
"picomatch": "^4.0.2"
|
"picomatch": "^4.0.2"
|
||||||
@@ -3349,11 +3386,26 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "11.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||||
|
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/esm/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.3.5",
|
"version": "6.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
||||||
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
|
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.4.4",
|
"fdir": "^6.4.4",
|
||||||
@@ -3423,6 +3475,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vite-plugin-devtools-json": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-plugin-devtools-json/-/vite-plugin-devtools-json-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-K7PoaWOEJECZ1n3VbhJXsUAX2PsO0xY7KFMM/Leh7tUev0M5zi+lz+vnVVdCK17IOK9Jp9rdzHXc08cnQirGbg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": "^11.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vite": "^2.7.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vitefu": {
|
"node_modules/vitefu": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "esn-code-scanner",
|
"name": "scan-wave",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"lint": "prettier --check ."
|
"lint": "prettier --check ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/kit": "^2.16.0",
|
"@sveltejs/kit": "^2.22.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
"@tailwindcss/vite": "^4.0.0",
|
"@tailwindcss/vite": "^4.0.0",
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"svelte-check": "^4.0.0",
|
"svelte-check": "^4.0.0",
|
||||||
"tailwindcss": "^4.0.0",
|
"tailwindcss": "^4.0.0",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^6.2.6"
|
"vite-plugin-devtools-json": "^0.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@supabase/ssr": "^0.6.1",
|
"@supabase/ssr": "^0.6.1",
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
<script>
|
<script>
|
||||||
import { invalidate } from '$app/navigation'
|
import { invalidate } from '$app/navigation';
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte';
|
||||||
import "../app.css";
|
import '../app.css';
|
||||||
|
|
||||||
let { data, children } = $props()
|
let { data, children } = $props();
|
||||||
let { session, supabase } = $derived(data)
|
let { session, supabase } = $derived(data);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const { data } = supabase.auth.onAuthStateChange((_, newSession) => {
|
const { data } = supabase.auth.onAuthStateChange((_, newSession) => {
|
||||||
if (newSession?.expires_at !== session?.expires_at) {
|
if (newSession?.expires_at !== session?.expires_at) {
|
||||||
invalidate('supabase:auth')
|
invalidate('supabase:auth');
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return () => data.subscription.unsubscribe()
|
return () => data.subscription.unsubscribe();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{@render children()}
|
<svelte:head>
|
||||||
|
<title>ScanWave</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
{@render children()}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<img class="w-32 h-auto" src="/qr-code.png" alt="">
|
<img class="w-32 h-auto" src="/qr-code.png" alt="">
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-3xl font-bold text-center mb-2">ESN Scanner App</h1>
|
<h1 class="text-3xl font-bold text-center mb-2">ScanWave</h1>
|
||||||
<h2 class="text-lg text-gray-600 text-center mb-8">Make entrance to your events a breeze.</h2>
|
<h2 class="text-lg text-gray-600 text-center mb-8">Make entrance to your events a breeze.</h2>
|
||||||
<div class="flex space-x-4 w-full justify-center">
|
<div class="flex space-x-4 w-full justify-center">
|
||||||
<a href="/private/home" class="w-64 py-2 bg-blue-600 text-white rounded-lg text-center hover:bg-blue-700 transition">Get started</a>
|
<a href="/private/home" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-full shadow-none border border-gray-300 w-64 text-center transition">
|
||||||
|
Get started
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,13 +2,18 @@
|
|||||||
// Add any navbar logic here if needed
|
// Add any navbar logic here if needed
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav class="bg-white border-b border-gray-300 text-gray-900 p-4 flex items-center justify-between">
|
<nav class="bg-gray-50 border-b border-gray-300 text-gray-900 p-2">
|
||||||
<div class="font-bold text-lg">ESN Scanner</div>
|
<div class="container max-w-2xl mx-auto p-2">
|
||||||
<ul class="flex space-x-4">
|
<div class="flex items-center justify-between">
|
||||||
<li><a href="/private/home" class="hover:underline">Home</a></li>
|
<div class="font-bold text-lg">ScanWave</div>
|
||||||
<li><a href="/private/scanner" class="hover:underline">Scanner</a></li>
|
|
||||||
<li><a href="/private/events" class="hover:underline">Events</a></li>
|
<ul class="flex space-x-4">
|
||||||
</ul>
|
<li><a href="/private/home" class="hover:underline">Home</a></li>
|
||||||
|
<li><a href="/private/scanner" class="hover:underline">Scanner</a></li>
|
||||||
|
<li><a href="/private/events" class="hover:underline">Events</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="container max-w-2xl mx-auto p-2 bg-white">
|
<div class="container max-w-2xl mx-auto p-2 bg-white">
|
||||||
|
|||||||
7
src/routes/private/events/+page.server.ts
Normal file
7
src/routes/private/events/+page.server.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export async function load({ locals }) {
|
||||||
|
const { data: events, error } = await locals.supabase
|
||||||
|
.from('events')
|
||||||
|
.select('*')
|
||||||
|
.order('date', { ascending: false });
|
||||||
|
return { events };
|
||||||
|
}
|
||||||
25
src/routes/private/events/+page.svelte
Normal file
25
src/routes/private/events/+page.svelte
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let data;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1 class="text-2xl font-bold mb-4 mt-2 text-center">All Events</h1>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 max-w-2xl mx-auto">
|
||||||
|
{#each data.events as event}
|
||||||
|
<a
|
||||||
|
href={`/private/events/event?id=${event.id}`}
|
||||||
|
class="block border border-gray-300 rounded bg-white p-4 shadow-none transition cursor-pointer hover:border-blue-500 group"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<span class="font-semibold text-lg text-black-700 group-hover:underline">{event.name}</span>
|
||||||
|
<span class="text-gray-500 text-sm">{event.date}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/private/creator"
|
||||||
|
class="fixed bottom-6 left-1/2 -translate-x-1/2 z-50 bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-full shadow-none border border-gray-300"
|
||||||
|
>
|
||||||
|
New Event
|
||||||
|
</a>
|
||||||
13
src/routes/private/events/event/+page.server.ts
Normal file
13
src/routes/private/events/event/+page.server.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export async function load({ locals, url }) {
|
||||||
|
const event_id = url.searchParams.get('id');
|
||||||
|
const { data: event_data, error: eventError } = await locals.supabase
|
||||||
|
.from('events')
|
||||||
|
.select('*')
|
||||||
|
.eq('id', event_id)
|
||||||
|
.single()
|
||||||
|
const { data: participants, error: participantsError } = await locals.supabase
|
||||||
|
.from('participants')
|
||||||
|
.select('*, scanned_by:profiles (id, display_name)')
|
||||||
|
.eq('event', event_id)
|
||||||
|
return {event_data, participants};
|
||||||
|
}
|
||||||
95
src/routes/private/events/event/+page.svelte
Normal file
95
src/routes/private/events/event/+page.svelte
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { data } = $props();
|
||||||
|
|
||||||
|
const scannedCount = data.participants.filter((p) => p.scanned).length;
|
||||||
|
const notScannedCount = data.participants.length - scannedCount;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1 class="mt-2 mb-4 text-center text-2xl font-bold">Event Overview</h1>
|
||||||
|
|
||||||
|
<div class="mb-2 rounded border border-gray-300 bg-white p-4">
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<span class="text-black-700 text-lg font-semibold">{data.event_data.name}</span>
|
||||||
|
<span class="text-black-500 text-sm">{data.event_data.date}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2 flex items-center rounded border border-gray-300 bg-white p-4">
|
||||||
|
<div class="flex flex-1 items-center justify-center gap-2">
|
||||||
|
<svg
|
||||||
|
class="inline h-4 w-4 text-green-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-sm text-gray-700">Scanned ({scannedCount})</span>
|
||||||
|
</div>
|
||||||
|
<div class="mx-4 h-8 w-px bg-gray-300"></div>
|
||||||
|
<div class="flex flex-1 items-center justify-center gap-2">
|
||||||
|
<svg
|
||||||
|
class="inline h-4 w-4 text-red-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" />
|
||||||
|
<line x1="8" y1="8" x2="16" y2="16" stroke="currentColor" stroke-width="2" />
|
||||||
|
<line x1="16" y1="8" x2="8" y2="16" stroke="currentColor" stroke-width="2" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-sm text-gray-700">Not scanned ({notScannedCount})</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rounded border border-gray-300 bg-white p-4">
|
||||||
|
<h2 class="mb-2 rounded text-xl font-bold">Participants ({data.participants.length})</h2>
|
||||||
|
<ul class="space-y-1">
|
||||||
|
{#each data.participants as p}
|
||||||
|
<li class="flex items-center gap-2 border-b pb-1 last:border-b-0">
|
||||||
|
{#if p.scanned}
|
||||||
|
<svg
|
||||||
|
title="Scanned"
|
||||||
|
class="mr-2 inline h-4 w-4 text-green-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
{:else}
|
||||||
|
<svg
|
||||||
|
title="Not scanned"
|
||||||
|
class="mr-2 inline h-4 w-4 text-red-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" />
|
||||||
|
<line x1="8" y1="8" x2="16" y2="16" stroke="currentColor" stroke-width="2" />
|
||||||
|
<line x1="16" y1="8" x2="8" y2="16" stroke="currentColor" stroke-width="2" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
<span class="font-semibold">{p.name} {p.surname}</span>
|
||||||
|
<span class="flex-1"></span>
|
||||||
|
{#if p.scanned_by}
|
||||||
|
<div class="flex flex-row items-end ml-2">
|
||||||
|
<span class="mr-1 text-xs text-gray-500">
|
||||||
|
{new Date(p.scanned_at).toLocaleTimeString([], {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
hour12: false
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
<span class="text-xs text-gray-500">by {p.scanned_by.display_name}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -7,13 +7,45 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="user-profile">
|
<h1 class="mt-2 mb-4 text-center text-2xl font-bold">User Profile</h1>
|
||||||
<h2 class="mb-2 text-2xl font-bold">Currently logged in</h2>
|
|
||||||
<p><strong>Username:</strong> {data.user?.user_metadata.display_name}</p>
|
<div class="mb-4 rounded border border-gray-300 bg-white p-6">
|
||||||
<p><strong>Email:</strong> {data.user?.email}</p>
|
<div class="flex flex-col gap-2">
|
||||||
<p><strong>Section:</strong> {data.user_profile?.section.name}</p>
|
<div class="flex items-center gap-3 mb-4">
|
||||||
<p><strong>Position:</strong> {data.user_profile?.section_position}</p>
|
<div class="h-12 w-12 rounded-full bg-gray-200 flex items-center justify-center text-xl font-bold text-gray-600">
|
||||||
|
{data.user?.user_metadata.display_name?.[0] ?? "U"}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="text-lg font-semibold text-gray-800">{data.user?.user_metadata.display_name}</span>
|
||||||
|
<div class="text-sm text-gray-500">{data.user?.email}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<div>
|
||||||
|
<span class="font-medium text-gray-700">Section:</span>
|
||||||
|
<span class="text-gray-900">{data.user_profile?.section.name ?? "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="font-medium text-gray-700">Position:</span>
|
||||||
|
<span class="text-gray-900">{data.user_profile?.section_position ?? "N/A"}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-lg mb-2 mt-4">User guide</h2>
|
||||||
|
<p class="text-gray-700 text-sm leading-relaxed">
|
||||||
|
To scan a QR code, head over to Scanner in the top right corner. Click on Start scanning and allow camera permissions.
|
||||||
|
If you close and open your browser and your camera is stuck, simply refresh the page or click Stop scanning and then Start scanning again.
|
||||||
|
When you scan a QR code, a request is sent to the server to get the user's personal information and to mark their tickets as scanned.
|
||||||
|
</p>
|
||||||
|
<h2 class="text-lg mb-2 mt-4">Administrator guide</h2>
|
||||||
|
<p class="text-gray-700 text-sm leading-relaxed">
|
||||||
|
You can view events
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="mt-4 rounded bg-red-500 px-4 py-2 text-white hover:bg-red-600">
|
|
||||||
<a href="/auth/signout">Sign out</a>
|
<a
|
||||||
</button>
|
href="/auth/signout"
|
||||||
|
class="fixed bottom-6 left-1/2 -translate-x-1/2 z-50 bg-red-500 hover:bg-red-600 text-white font-semibold py-3 px-8 rounded-full shadow-none border border-gray-300 transition"
|
||||||
|
>
|
||||||
|
Sign out
|
||||||
|
</a>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
scan_state = ScanState.scanning;
|
scan_state = ScanState.scanning;
|
||||||
|
|
||||||
data.supabase
|
data.supabase
|
||||||
.from('qrcodes')
|
.from('participants')
|
||||||
.select(`*, event ( id, name ), scanned_by ( id, display_name )`)
|
.select(`*, event ( id, name ), scanned_by ( id, display_name )`)
|
||||||
.eq('id', scanned_id)
|
.eq('id', scanned_id)
|
||||||
.then( response => {
|
.then( response => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import {
|
import {
|
||||||
Html5QrcodeScanner,
|
Html5QrcodeScanner,
|
||||||
type Html5QrcodeResult,
|
type Html5QrcodeResult,
|
||||||
@@ -37,6 +37,12 @@
|
|||||||
);
|
);
|
||||||
scanner.render(onScanSuccess, onScanFailure);
|
scanner.render(onScanSuccess, onScanFailure);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (scanner) {
|
||||||
|
scanner.clear().catch(() => {});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id="qr-scanner" class="w-full h-full max-w-none overflow-hidden rounded-sm"></div>
|
<div id="qr-scanner" class="w-full h-full max-w-none overflow-hidden rounded-sm"></div>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import devtoolsJson from 'vite-plugin-devtools-json';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [tailwindcss(), sveltekit()]
|
plugins: [tailwindcss(), sveltekit(), devtoolsJson()]
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user