diff --git a/.gitignore b/.gitignore
index e93ba06..52b7f64 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,4 +28,5 @@ coverage
*.sw?
*.timestamp*.mjs
-.env
\ No newline at end of file
+.env
+*.env
\ No newline at end of file
diff --git a/compose.yaml b/compose.yaml
index cb1fd49..ad477ec 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -1,10 +1,19 @@
services:
- server:
+ frontend:
build:
context: .
environment:
- NODE_ENV: production
- IN_CONTAINER: true
+ - NODE_ENV=production
+ - IN_CONTAINER=true
ports:
- 50000:80 # .com
- 50001:81 # .nl
+ backend:
+ image: ghcr.io/jonathanbout/portfolio-backend:release
+ env_file: backend.compose.env
+ environment:
+ - ASPNETCORE_ENVIRONMENT=Production
+ - ASPNETCORE_URLS=http://+:5000
+ - CORS_ALLOWED_ORIGINS=http://localhost:50000,http://localhost:50001
+ ports:
+ - 32769:5000
diff --git a/env.d.ts b/env.d.ts
index 97746b0..bcf87da 100644
--- a/env.d.ts
+++ b/env.d.ts
@@ -1,4 +1,12 @@
///
+import type { Locale } from "@/localizer"
import "module"
+declare global {
+ interface Window {
+ app: {
+ locale: Locale
+ }
+ }
+}
\ No newline at end of file
diff --git a/nginx/default.conf b/nginx/default.conf
index c7ddf99..d8063e6 100644
--- a/nginx/default.conf
+++ b/nginx/default.conf
@@ -9,10 +9,10 @@ server {
root /app;
- index index.nl.html;
+ index nl/index.html;
location / {
- try_files $uri $uri/ /index.nl.html;
+ try_files $uri $uri/ /nl/index.html;
}
include shared_cache.conf;
@@ -25,10 +25,10 @@ server {
root /app;
- index index.en.html;
+ index en/index.html;
location / {
- try_files $uri $uri/ /index.en.html;
+ try_files $uri $uri/ /en/index.html;
}
include shared_cache.conf;
diff --git a/package-lock.json b/package-lock.json
index 3a21139..9a18dc2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,14 +8,14 @@
"name": "portfolio",
"version": "0.0.0",
"dependencies": {
- "@typescript-eslint/parser": "^8.12.1",
+ "@typescript-eslint/parser": "^8.12.2",
"bootstrap-icons": "^1.11.3",
"eslint-plugin-vue": "^9.30.0",
"flag-icons": "^7.2.3",
"npm-run-all": "^4.1.5",
"parse-css-color": "^0.2.1",
"read-last-lines": "^1.8.0",
- "typescript-eslint": "^8.12.1",
+ "typescript-eslint": "^8.12.2",
"vue": "^3.5.12",
"vue-eslint-parser": "^9.4.3",
"vue-i18n": "^10.0.4",
@@ -24,7 +24,7 @@
"devDependencies": {
"@babel/types": "^7.26.0",
"@tsconfig/node18": "^18.2.4",
- "@types/node": "^22.8.2",
+ "@types/node": "^22.8.5",
"@vitejs/plugin-vue": "^5.1.4",
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.20",
@@ -33,8 +33,8 @@
"prettier": "^3.3.3",
"typescript": "~5.6.3",
"vite": "^5.4.10",
- "vite-plugin-vue-devtools": "^7.5.4",
- "vue-tsc": "^2.1.8"
+ "vite-plugin-vue-devtools": "^7.5.6",
+ "vue-tsc": "^2.1.10"
}
},
"node_modules/@ampproject/remapping": {
@@ -1600,24 +1600,24 @@
"peer": true
},
"node_modules/@types/node": {
- "version": "22.8.2",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.2.tgz",
- "integrity": "sha512-NzaRNFV+FZkvK/KLCsNdTvID0SThyrs5SHB6tsD/lajr22FGC73N2QeDPM2wHtVde8mgcXuSsHQkH5cX1pbPLw==",
+ "version": "22.8.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.5.tgz",
+ "integrity": "sha512-5iYk6AMPtsMbkZqCO1UGF9W5L38twq11S2pYWkybGHH2ogPUvXWNlQqJBzuEZWKj/WRH+QTeiv6ySWqJtvIEgA==",
"dev": true,
"dependencies": {
"undici-types": "~6.19.8"
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.1.tgz",
- "integrity": "sha512-gNg/inLRcPoBsKKIe4Vv38SVSOhk4BKWNO0T56sVff33gRqtTpOsrhHtiOKD1lmIOmCtZMPaW2x/h2FlM+sCEg==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz",
+ "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.12.1",
- "@typescript-eslint/type-utils": "8.12.1",
- "@typescript-eslint/utils": "8.12.1",
- "@typescript-eslint/visitor-keys": "8.12.1",
+ "@typescript-eslint/scope-manager": "8.12.2",
+ "@typescript-eslint/type-utils": "8.12.2",
+ "@typescript-eslint/utils": "8.12.2",
+ "@typescript-eslint/visitor-keys": "8.12.2",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@@ -1641,14 +1641,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.1.tgz",
- "integrity": "sha512-I/I9Bg7qFa8rOgBnUUHIWTgzbB5wVkSLX+04xGUzTcJUtdq/I2uHWR9mbW6qUYJG/UmkuDcTax5JHvoEWOAHOQ==",
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.12.1",
- "@typescript-eslint/types": "8.12.1",
- "@typescript-eslint/typescript-estree": "8.12.1",
- "@typescript-eslint/visitor-keys": "8.12.1",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz",
+ "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.12.2",
+ "@typescript-eslint/types": "8.12.2",
+ "@typescript-eslint/typescript-estree": "8.12.2",
+ "@typescript-eslint/visitor-keys": "8.12.2",
"debug": "^4.3.4"
},
"engines": {
@@ -1750,12 +1750,12 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.1.tgz",
- "integrity": "sha512-bma6sD1iViTt+y9MAwDlBdPTMCqoH/BNdcQk4rKhIZWv3eM0xHmzeSrPJA663PAqFqfpOmtdugycpr0E1mZDVA==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz",
+ "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==",
"dependencies": {
- "@typescript-eslint/types": "8.12.1",
- "@typescript-eslint/visitor-keys": "8.12.1"
+ "@typescript-eslint/types": "8.12.2",
+ "@typescript-eslint/visitor-keys": "8.12.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1766,12 +1766,12 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.1.tgz",
- "integrity": "sha512-zJzrvbDVjIzVKV2TGHcjembEhws8RWXJhmqfO9hS2gRXBN0gDwGhRPEdJ6AZglzfJ+YA1q09EWpSLSXjBJpIMQ==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz",
+ "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==",
"dependencies": {
- "@typescript-eslint/typescript-estree": "8.12.1",
- "@typescript-eslint/utils": "8.12.1",
+ "@typescript-eslint/typescript-estree": "8.12.2",
+ "@typescript-eslint/utils": "8.12.2",
"debug": "^4.3.4",
"ts-api-utils": "^1.3.0"
},
@@ -1789,9 +1789,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.1.tgz",
- "integrity": "sha512-anMS4es5lxBe4UVcDXOkcDb3csnm5BvaNIbOFfvy/pJEohorsggdVB8MFbl5EZiEuBnZZ0ei1z7W5b6FdFiV1Q==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz",
+ "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -1801,12 +1801,12 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.1.tgz",
- "integrity": "sha512-k/o9khHOckPeDXilFTIPsP9iAYhhdMh3OsOL3i2072PNpFqhqzRHx472/0DeC8H/WZee3bZG0z2ddGRSPgeOKw==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz",
+ "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==",
"dependencies": {
- "@typescript-eslint/types": "8.12.1",
- "@typescript-eslint/visitor-keys": "8.12.1",
+ "@typescript-eslint/types": "8.12.2",
+ "@typescript-eslint/visitor-keys": "8.12.2",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@@ -1828,14 +1828,14 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.1.tgz",
- "integrity": "sha512-sDv9yFHrhKe1WN8EYuzfhKCh/sFRupe9P+m/lZ5YgVvPoCUGHNN50IO4llSu7JAbftUM/QcCh+GeCortXPrBYQ==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz",
+ "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "8.12.1",
- "@typescript-eslint/types": "8.12.1",
- "@typescript-eslint/typescript-estree": "8.12.1"
+ "@typescript-eslint/scope-manager": "8.12.2",
+ "@typescript-eslint/types": "8.12.2",
+ "@typescript-eslint/typescript-estree": "8.12.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1849,11 +1849,11 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.1.tgz",
- "integrity": "sha512-2RwdwnNGuOQKdGjuhujQHUqBZhEuodg2sLVPvOfWktvA9sOXOVqARjOyHSyhN2LiJGKxV6c8oOcmOtRcAnEeFw==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz",
+ "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==",
"dependencies": {
- "@typescript-eslint/types": "8.12.1",
+ "@typescript-eslint/types": "8.12.2",
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
@@ -2049,13 +2049,13 @@
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="
},
"node_modules/@vue/devtools-core": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.5.4.tgz",
- "integrity": "sha512-igB2iUKsCUrXkp0wKLn3n5X8jz3AgXWk7if0QpLu3Do16QmlTO0e+/VvTpX0ZbLMh8OOAxDKyfPvJMMO/4QJ5w==",
+ "version": "7.5.6",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.5.6.tgz",
+ "integrity": "sha512-Y/hqXk3sTdqAutWqb2KVisnxUMubzo3fHuSOgmSJ/Ok09yCxYdY7ztCDGWUdgVQQVQKGD84yefYwStutvLOeuA==",
"dev": true,
"dependencies": {
- "@vue/devtools-kit": "^7.5.4",
- "@vue/devtools-shared": "^7.5.4",
+ "@vue/devtools-kit": "^7.5.6",
+ "@vue/devtools-shared": "^7.5.6",
"mitt": "^3.0.1",
"nanoid": "^3.3.4",
"pathe": "^1.1.2",
@@ -2066,12 +2066,12 @@
}
},
"node_modules/@vue/devtools-kit": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.5.4.tgz",
- "integrity": "sha512-0i7WFgc1B2TL52tstn82zlb9opSA0aIiHfkUYFXtZb8CIpmlFMTkHtgwVl6PMWNBj3LNhYou1YJCLpCYvJYYoA==",
+ "version": "7.5.6",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.5.6.tgz",
+ "integrity": "sha512-44qr4/l9BsNP5hKETucueP8SKkyDZBHEurV4pQnRWs906OG9f2aYWhk4vL+27tsB4ZoWJM2h3RLhygzeeKZzWg==",
"dev": true,
"dependencies": {
- "@vue/devtools-shared": "^7.5.4",
+ "@vue/devtools-shared": "^7.5.6",
"birpc": "^0.2.19",
"hookable": "^5.5.3",
"mitt": "^3.0.1",
@@ -2081,18 +2081,18 @@
}
},
"node_modules/@vue/devtools-shared": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.5.4.tgz",
- "integrity": "sha512-dwuq4YmwTyLc7eBOqX63s3JB8il7qnKsNgENglSMkUPwiItHkVAYYfPESN1rxSdYkl1RCux1l5TBidYqfUDNAA==",
+ "version": "7.5.6",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.5.6.tgz",
+ "integrity": "sha512-5iq/BF6f05JTcC7J/1DTUm4CpyVVB4KiyLAo/fDcoyWR7EulharWQVbr6W7ek5lO23f5mbnJ+adA5tfFTJt6Sw==",
"dev": true,
"dependencies": {
"rfdc": "^1.4.1"
}
},
"node_modules/@vue/language-core": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.1.8.tgz",
- "integrity": "sha512-DtPUKrIRqqzY1joGfVHxHWZoxXZbCQLmVtW+QTifuPInfcs1R/3UAdlJXDp+lpSpP9lI5m+jMYYlwDXXu3KSTg==",
+ "version": "2.1.10",
+ "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.1.10.tgz",
+ "integrity": "sha512-DAI289d0K3AB5TUG3xDp9OuQ71CnrujQwJrQnfuZDwo6eGNf0UoRlPuaVNO+Zrn65PC3j0oB2i7mNmVPggeGeQ==",
"dev": true,
"dependencies": {
"@volar/language-core": "~2.4.8",
@@ -5948,37 +5948,13 @@
}
},
"node_modules/typescript-eslint": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.12.1.tgz",
- "integrity": "sha512-SsKedZnq4TStkrpqnk+OqTnmkC9CkYBRNKjQ965CLpFruGcRkPF5UhKxbcbF6c/m2r6YAgKw/UtQxdlMjh3mug==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.12.2.tgz",
+ "integrity": "sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==",
"dependencies": {
- "@typescript-eslint/eslint-plugin": "8.12.1",
- "@typescript-eslint/parser": "8.12.1",
- "@typescript-eslint/utils": "8.12.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.11.0.tgz",
- "integrity": "sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==",
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.11.0",
- "@typescript-eslint/types": "8.11.0",
- "@typescript-eslint/typescript-estree": "8.11.0",
- "@typescript-eslint/visitor-keys": "8.11.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/eslint-plugin": "8.12.2",
+ "@typescript-eslint/parser": "8.12.2",
+ "@typescript-eslint/utils": "8.12.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -6189,14 +6165,14 @@
}
},
"node_modules/vite-plugin-vue-devtools": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.5.4.tgz",
- "integrity": "sha512-6yTcGrF+YdplDhNiNCkwj23BQDHA/jp06FR4Bo3rui1GW+8VdFcc26au2gtynPwRDNJXNueTxiVtVb6dq+lNZA==",
+ "version": "7.5.6",
+ "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.5.6.tgz",
+ "integrity": "sha512-RkKiY7NYfxwjTt8PTV1Z4d8nzP2afGcAvNzwyXsCTBF5qQZJ/hckbdamN6z9JpmlNJoG07dQsy3vXK5ElFIIxw==",
"dev": true,
"dependencies": {
- "@vue/devtools-core": "^7.5.4",
- "@vue/devtools-kit": "^7.5.4",
- "@vue/devtools-shared": "^7.5.4",
+ "@vue/devtools-core": "^7.5.6",
+ "@vue/devtools-kit": "^7.5.6",
+ "@vue/devtools-shared": "^7.5.6",
"execa": "^8.0.1",
"sirv": "^3.0.0",
"vite-plugin-inspect": "^0.8.7",
@@ -6372,13 +6348,13 @@
}
},
"node_modules/vue-tsc": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.1.8.tgz",
- "integrity": "sha512-6+vjb7JLxKIzeD/1ktoUBZGAr+148FQoEFl8Lv5EpDJLO2PrUalhp7atMEuzEkLnoooM5bg3pJqjZI+oobxIaQ==",
+ "version": "2.1.10",
+ "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.1.10.tgz",
+ "integrity": "sha512-RBNSfaaRHcN5uqVqJSZh++Gy/YUzryuv9u1aFWhsammDJXNtUiJMNoJ747lZcQ68wUQFx6E73y4FY3D8E7FGMA==",
"dev": true,
"dependencies": {
"@volar/typescript": "~2.4.8",
- "@vue/language-core": "2.1.8",
+ "@vue/language-core": "2.1.10",
"semver": "^7.5.4"
},
"bin": {
diff --git a/package.json b/package.json
index 5fdbaa9..936d2d8 100644
--- a/package.json
+++ b/package.json
@@ -14,14 +14,14 @@
"compose-up": "docker compose up --build"
},
"dependencies": {
- "@typescript-eslint/parser": "^8.12.1",
+ "@typescript-eslint/parser": "^8.12.2",
"bootstrap-icons": "^1.11.3",
"eslint-plugin-vue": "^9.30.0",
"flag-icons": "^7.2.3",
"npm-run-all": "^4.1.5",
"parse-css-color": "^0.2.1",
"read-last-lines": "^1.8.0",
- "typescript-eslint": "^8.12.1",
+ "typescript-eslint": "^8.12.2",
"vue": "^3.5.12",
"vue-eslint-parser": "^9.4.3",
"vue-i18n": "^10.0.4",
@@ -30,7 +30,7 @@
"devDependencies": {
"@babel/types": "^7.26.0",
"@tsconfig/node18": "^18.2.4",
- "@types/node": "^22.8.2",
+ "@types/node": "^22.8.5",
"@vitejs/plugin-vue": "^5.1.4",
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.20",
@@ -39,7 +39,7 @@
"prettier": "^3.3.3",
"typescript": "~5.6.3",
"vite": "^5.4.10",
- "vite-plugin-vue-devtools": "^7.5.4",
- "vue-tsc": "^2.1.8"
+ "vite-plugin-vue-devtools": "^7.5.6",
+ "vue-tsc": "^2.1.10"
}
}
diff --git a/plugins/localizer.plugin.ts b/plugins/localizer.plugin.ts
index 1c8bb22..8464ad4 100644
--- a/plugins/localizer.plugin.ts
+++ b/plugins/localizer.plugin.ts
@@ -9,18 +9,20 @@ function getFiles(bundle: OutputBundle): { [key: string]: (OutputAsset | OutputB
const { fileName } = file
const extension = extname(fileName).substring(1)
- result[extension] = (result[extension] || []).concat(file as any)
+ result[extension] = (result[extension] || []).concat(file as OutputAsset)
}
return result
}
-function doReplace(oldHtml: string, key: string, value: any) {
+type LocaleData = string | { [key: string]: LocaleData }
+
+function doReplace(oldHtml: string, key: string, value: LocaleData): string {
if (typeof value === "string") {
// match [[localize:key]] but not \[[localize:key]]
return oldHtml.replace(new RegExp(`(? locale !== "common")
for (const locale of allLocales) {
- const newFileName = `index.${locale}.html`
+ const newFileName = `${locale}/index.html`
let newHtml = html
- const pairs = Object.entries(json[locale]).concat(commonKeys)
+ const pairs = Object.entries(json[locale]).concat(commonKeys) as [string, LocaleData][]
for (const [key, value] of pairs) {
newHtml = doReplace(newHtml, key, value)
@@ -75,6 +77,8 @@ export default function localizerPlugin(): Plugin {
newHtml =
"\n" + newHtml
+ newHtml = newHtml.replace("
", ``)
+
const htmlFile: EmittedAsset = {
type: "asset",
source: newHtml,
diff --git a/src/assets/base.less b/src/assets/base.less
index 4b32319..901c2df 100644
--- a/src/assets/base.less
+++ b/src/assets/base.less
@@ -55,7 +55,7 @@
local("Cascadia Code"),
url("https://static.jonathanbout.dev/CascadiaCode/woff2/CascadiaCode.woff2") format("woff2"),
url("https://static.jonathanbout.dev/CascadiaCode/ttf/CascadiaCode.ttf") format("truetype"),
- url("https://static.jonathanbout.dev/CascadiaCode/otf/static/CascadiaCodeNF-Regular.otf") format("opentype"),
+url("https://static.jonathanbout.dev/CascadiaCode/CascadiaCode.ttf") format("truetype"), url("https://static.jonathanbout.dev/CascadiaCode/otf/static/CascadiaCodeNF-Regular.otf") format("opentype"),
local("Cascadia Mono"),
monospace;
}
diff --git a/src/localizer/index.ts b/src/localizer/index.ts
index 5b4e7bf..fcc773c 100644
--- a/src/localizer/index.ts
+++ b/src/localizer/index.ts
@@ -74,7 +74,7 @@ export function createLocalizer(): VuePlugin {
* 6. If none of the above, use the locale for the current domain (.com is English, .nl is Dutch)
*/
- let locale: Locale = "en"
+ let locale: Locale = window.app.locale
for (const loc of LOCALES) {
if (window.location.origin.toLowerCase() === domainsByLocale[loc].toLowerCase()) {
diff --git a/src/backend/index.ts b/src/server/index.ts
similarity index 91%
rename from src/backend/index.ts
rename to src/server/index.ts
index c66823d..2f5ffab 100644
--- a/src/backend/index.ts
+++ b/src/server/index.ts
@@ -6,7 +6,11 @@ export type Body = { [key: string]: unknown }
const productionUrl = ""
function configuredBaseUrl() {
- return import.meta.env.PROD ? productionUrl : (import.meta.env.VITE_BACKEND_URL as string) || productionUrl
+ const url = import.meta.env.VITE_BACKEND_URL || productionUrl
+
+ console.debug(`got base url ${url}`)
+
+ return url
}
function getPath(route: Route = "/", query: QueryParameters) {
diff --git a/src/stats/index.ts b/src/stats/index.ts
index 3f0be20..c9eedbf 100644
--- a/src/stats/index.ts
+++ b/src/stats/index.ts
@@ -1,5 +1,5 @@
import { CSSColor, contrastingColor } from "@/util/color"
-import backend from "@/backend"
+import server from "@/server"
export class TopLanguage {
name: string = ""
color: CSSColor = new CSSColor()
@@ -57,7 +57,7 @@ export async function getStats() {
try {
console.debug("fetching stats")
- const response = await backend.get("/api/top-languages", { exclude_langs: "HLSL,ShaderLab" })
+ const response = await server.get("/api/top-languages", { exclude_langs: "HLSL,ShaderLab" })
const data = (await response.json()) as { [key: string]: unknown }[]
diff --git a/vite.config.ts b/vite.config.ts
index 72a2ff5..a9a72db 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -21,7 +21,11 @@ export default defineConfig({
usePolling: true
},
port: 3999,
- strictPort: true,
+ strictPort: true
+ },
+ preview: {
+ port: 3999,
+ strictPort: true
},
css: {
preprocessorOptions: {