Compare commits
12 Commits
a0c3b27aab
...
chore/soft
Author | SHA1 | Date | |
---|---|---|---|
2c5d3c04d0 | |||
2a1cbb8be3 | |||
24720b782e | |||
0b299b9410 | |||
03b95a6c8c | |||
63c84e1430 | |||
9028175ae4
|
|||
280c8e15ad
|
|||
e081a0cb3e
|
|||
41c6964679 | |||
f25c6ddd68 | |||
9b49710556
|
25
.gitea/workflows/test.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: Run Unit and Integration Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
- "development"
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Run Tests
|
||||||
|
run: npm test
|
16
.prettierrc
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"plugins": ["prettier-plugin-svelte"],
|
"plugins": ["prettier-plugin-svelte"],
|
||||||
"pluginSearchDirs": ["."],
|
"pluginSearchDirs": ["."],
|
||||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@ This site contains information relating to my personal situation, however, you a
|
|||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/images/main_page.png" width="40%">
|
<img src="assets/images/main.png" width="40%">
|
||||||
<img src="assets/images/light_mode.png" width="40%">
|
<img src="assets/images/light_mode.png" width="40%">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -25,17 +25,20 @@ Get starting but installing all of the dependencies of the project.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm run dev
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# or start the server and open the app in a new browser tab
|
# or start the server and open the app in a new browser tab
|
||||||
npm run dev -- --open
|
npm run dev -- --open
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
@@ -45,6 +48,7 @@ To create a production version of the app:
|
|||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You can preview the production build with `npm run preview`.
|
You can preview the production build with `npm run preview`.
|
||||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 181 KiB |
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 166 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 298 KiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 85 KiB |
@@ -5,6 +5,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
"test": "vitest run",
|
||||||
|
"test:watch": "vitest",
|
||||||
"start": "export PORT=3000 && node ./build",
|
"start": "export PORT=3000 && node ./build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
@@ -24,7 +26,8 @@
|
|||||||
"svelte-check": "4.1.7",
|
"svelte-check": "4.1.7",
|
||||||
"tslib": "2.8.1",
|
"tslib": "2.8.1",
|
||||||
"typescript": "5.8.3",
|
"typescript": "5.8.3",
|
||||||
"vite": "6.3.5"
|
"vite": "6.3.5",
|
||||||
|
"vitest": "^3.1.4"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
286
pnpm-lock.yaml
generated
@@ -54,6 +54,9 @@ importers:
|
|||||||
vite:
|
vite:
|
||||||
specifier: 6.3.5
|
specifier: 6.3.5
|
||||||
version: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
version: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||||
|
vitest:
|
||||||
|
specifier: ^3.1.4
|
||||||
|
version: 3.1.4(jiti@2.4.2)(lightningcss@1.29.2)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -510,6 +513,35 @@ packages:
|
|||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
|
|
||||||
|
'@vitest/expect@3.1.4':
|
||||||
|
resolution: {integrity: sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==}
|
||||||
|
|
||||||
|
'@vitest/mocker@3.1.4':
|
||||||
|
resolution: {integrity: sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==}
|
||||||
|
peerDependencies:
|
||||||
|
msw: ^2.4.9
|
||||||
|
vite: ^5.0.0 || ^6.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
msw:
|
||||||
|
optional: true
|
||||||
|
vite:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@vitest/pretty-format@3.1.4':
|
||||||
|
resolution: {integrity: sha512-cqv9H9GvAEoTaoq+cYqUTCGscUjKqlJZC7PRwY5FMySVj5J+xOm1KQcCiYHJOEzOKRUhLH4R2pTwvFlWCEScsg==}
|
||||||
|
|
||||||
|
'@vitest/runner@3.1.4':
|
||||||
|
resolution: {integrity: sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==}
|
||||||
|
|
||||||
|
'@vitest/snapshot@3.1.4':
|
||||||
|
resolution: {integrity: sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==}
|
||||||
|
|
||||||
|
'@vitest/spy@3.1.4':
|
||||||
|
resolution: {integrity: sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==}
|
||||||
|
|
||||||
|
'@vitest/utils@3.1.4':
|
||||||
|
resolution: {integrity: sha512-yriMuO1cfFhmiGc8ataN51+9ooHRuURdfAZfwFd3usWynjzpLslZdYnRegTv32qdgtJTsj15FoeZe2g15fY1gg==}
|
||||||
|
|
||||||
acorn@8.14.1:
|
acorn@8.14.1:
|
||||||
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
|
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
@@ -519,10 +551,26 @@ packages:
|
|||||||
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
|
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
assertion-error@2.0.1:
|
||||||
|
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
axobject-query@4.1.0:
|
axobject-query@4.1.0:
|
||||||
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
|
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
cac@6.7.14:
|
||||||
|
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
chai@5.2.0:
|
||||||
|
resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
check-error@2.1.1:
|
||||||
|
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
|
||||||
|
engines: {node: '>= 16'}
|
||||||
|
|
||||||
chokidar@4.0.3:
|
chokidar@4.0.3:
|
||||||
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
||||||
engines: {node: '>= 14.16.0'}
|
engines: {node: '>= 14.16.0'}
|
||||||
@@ -551,6 +599,10 @@ packages:
|
|||||||
supports-color:
|
supports-color:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
deep-eql@5.0.2:
|
||||||
|
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
deepmerge@4.3.1:
|
deepmerge@4.3.1:
|
||||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -566,6 +618,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
|
es-module-lexer@1.7.0:
|
||||||
|
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
|
||||||
|
|
||||||
esbuild@0.25.4:
|
esbuild@0.25.4:
|
||||||
resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
|
resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -580,6 +635,13 @@ packages:
|
|||||||
estree-walker@2.0.2:
|
estree-walker@2.0.2:
|
||||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
|
|
||||||
|
estree-walker@3.0.3:
|
||||||
|
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
|
||||||
|
|
||||||
|
expect-type@1.2.1:
|
||||||
|
resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
fdir@6.4.4:
|
fdir@6.4.4:
|
||||||
resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
|
resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -694,6 +756,9 @@ packages:
|
|||||||
locate-character@3.0.0:
|
locate-character@3.0.0:
|
||||||
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
|
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
|
||||||
|
|
||||||
|
loupe@3.1.3:
|
||||||
|
resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
|
||||||
|
|
||||||
magic-string@0.30.17:
|
magic-string@0.30.17:
|
||||||
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
||||||
|
|
||||||
@@ -729,6 +794,13 @@ packages:
|
|||||||
path-parse@1.0.7:
|
path-parse@1.0.7:
|
||||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||||
|
|
||||||
|
pathe@2.0.3:
|
||||||
|
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||||
|
|
||||||
|
pathval@2.0.0:
|
||||||
|
resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
|
||||||
|
engines: {node: '>= 14.16'}
|
||||||
|
|
||||||
picocolors@1.1.1:
|
picocolors@1.1.1:
|
||||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
@@ -772,6 +844,9 @@ packages:
|
|||||||
set-cookie-parser@2.7.1:
|
set-cookie-parser@2.7.1:
|
||||||
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
||||||
|
|
||||||
|
siginfo@2.0.0:
|
||||||
|
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||||
|
|
||||||
sirv@3.0.1:
|
sirv@3.0.1:
|
||||||
resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
|
resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -780,6 +855,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
stackback@0.0.2:
|
||||||
|
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
||||||
|
|
||||||
|
std-env@3.9.0:
|
||||||
|
resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0:
|
supports-preserve-symlinks-flag@1.0.0:
|
||||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -810,10 +891,28 @@ packages:
|
|||||||
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
|
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
tinybench@2.9.0:
|
||||||
|
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
||||||
|
|
||||||
|
tinyexec@0.3.2:
|
||||||
|
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
|
||||||
|
|
||||||
tinyglobby@0.2.13:
|
tinyglobby@0.2.13:
|
||||||
resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
|
resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
|
tinypool@1.1.0:
|
||||||
|
resolution: {integrity: sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==}
|
||||||
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
|
|
||||||
|
tinyrainbow@2.0.0:
|
||||||
|
resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
|
||||||
|
tinyspy@3.0.2:
|
||||||
|
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
|
||||||
totalist@3.0.1:
|
totalist@3.0.1:
|
||||||
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -826,6 +925,11 @@ packages:
|
|||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
vite-node@3.1.4:
|
||||||
|
resolution: {integrity: sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==}
|
||||||
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
vite@6.3.5:
|
vite@6.3.5:
|
||||||
resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
|
resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
|
||||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
@@ -874,6 +978,39 @@ packages:
|
|||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
vitest@3.1.4:
|
||||||
|
resolution: {integrity: sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==}
|
||||||
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@edge-runtime/vm': '*'
|
||||||
|
'@types/debug': ^4.1.12
|
||||||
|
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
|
||||||
|
'@vitest/browser': 3.1.4
|
||||||
|
'@vitest/ui': 3.1.4
|
||||||
|
happy-dom: '*'
|
||||||
|
jsdom: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@edge-runtime/vm':
|
||||||
|
optional: true
|
||||||
|
'@types/debug':
|
||||||
|
optional: true
|
||||||
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
'@vitest/browser':
|
||||||
|
optional: true
|
||||||
|
'@vitest/ui':
|
||||||
|
optional: true
|
||||||
|
happy-dom:
|
||||||
|
optional: true
|
||||||
|
jsdom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
why-is-node-running@2.3.0:
|
||||||
|
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
yallist@5.0.0:
|
yallist@5.0.0:
|
||||||
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
|
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -1215,12 +1352,66 @@ snapshots:
|
|||||||
|
|
||||||
'@types/resolve@1.20.2': {}
|
'@types/resolve@1.20.2': {}
|
||||||
|
|
||||||
|
'@vitest/expect@3.1.4':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/spy': 3.1.4
|
||||||
|
'@vitest/utils': 3.1.4
|
||||||
|
chai: 5.2.0
|
||||||
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
|
'@vitest/mocker@3.1.4(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/spy': 3.1.4
|
||||||
|
estree-walker: 3.0.3
|
||||||
|
magic-string: 0.30.17
|
||||||
|
optionalDependencies:
|
||||||
|
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||||
|
|
||||||
|
'@vitest/pretty-format@3.1.4':
|
||||||
|
dependencies:
|
||||||
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
|
'@vitest/runner@3.1.4':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/utils': 3.1.4
|
||||||
|
pathe: 2.0.3
|
||||||
|
|
||||||
|
'@vitest/snapshot@3.1.4':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/pretty-format': 3.1.4
|
||||||
|
magic-string: 0.30.17
|
||||||
|
pathe: 2.0.3
|
||||||
|
|
||||||
|
'@vitest/spy@3.1.4':
|
||||||
|
dependencies:
|
||||||
|
tinyspy: 3.0.2
|
||||||
|
|
||||||
|
'@vitest/utils@3.1.4':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/pretty-format': 3.1.4
|
||||||
|
loupe: 3.1.3
|
||||||
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
acorn@8.14.1: {}
|
acorn@8.14.1: {}
|
||||||
|
|
||||||
aria-query@5.3.2: {}
|
aria-query@5.3.2: {}
|
||||||
|
|
||||||
|
assertion-error@2.0.1: {}
|
||||||
|
|
||||||
axobject-query@4.1.0: {}
|
axobject-query@4.1.0: {}
|
||||||
|
|
||||||
|
cac@6.7.14: {}
|
||||||
|
|
||||||
|
chai@5.2.0:
|
||||||
|
dependencies:
|
||||||
|
assertion-error: 2.0.1
|
||||||
|
check-error: 2.1.1
|
||||||
|
deep-eql: 5.0.2
|
||||||
|
loupe: 3.1.3
|
||||||
|
pathval: 2.0.0
|
||||||
|
|
||||||
|
check-error@2.1.1: {}
|
||||||
|
|
||||||
chokidar@4.0.3:
|
chokidar@4.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
readdirp: 4.1.2
|
readdirp: 4.1.2
|
||||||
@@ -1237,6 +1428,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
|
deep-eql@5.0.2: {}
|
||||||
|
|
||||||
deepmerge@4.3.1: {}
|
deepmerge@4.3.1: {}
|
||||||
|
|
||||||
detect-libc@2.0.4: {}
|
detect-libc@2.0.4: {}
|
||||||
@@ -1248,6 +1441,8 @@ snapshots:
|
|||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
tapable: 2.2.1
|
tapable: 2.2.1
|
||||||
|
|
||||||
|
es-module-lexer@1.7.0: {}
|
||||||
|
|
||||||
esbuild@0.25.4:
|
esbuild@0.25.4:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/aix-ppc64': 0.25.4
|
'@esbuild/aix-ppc64': 0.25.4
|
||||||
@@ -1284,6 +1479,12 @@ snapshots:
|
|||||||
|
|
||||||
estree-walker@2.0.2: {}
|
estree-walker@2.0.2: {}
|
||||||
|
|
||||||
|
estree-walker@3.0.3:
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.7
|
||||||
|
|
||||||
|
expect-type@1.2.1: {}
|
||||||
|
|
||||||
fdir@6.4.4(picomatch@4.0.2):
|
fdir@6.4.4(picomatch@4.0.2):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.2
|
picomatch: 4.0.2
|
||||||
@@ -1366,6 +1567,8 @@ snapshots:
|
|||||||
|
|
||||||
locate-character@3.0.0: {}
|
locate-character@3.0.0: {}
|
||||||
|
|
||||||
|
loupe@3.1.3: {}
|
||||||
|
|
||||||
magic-string@0.30.17:
|
magic-string@0.30.17:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
@@ -1388,6 +1591,10 @@ snapshots:
|
|||||||
|
|
||||||
path-parse@1.0.7: {}
|
path-parse@1.0.7: {}
|
||||||
|
|
||||||
|
pathe@2.0.3: {}
|
||||||
|
|
||||||
|
pathval@2.0.0: {}
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
picomatch@4.0.2: {}
|
picomatch@4.0.2: {}
|
||||||
@@ -1445,6 +1652,8 @@ snapshots:
|
|||||||
|
|
||||||
set-cookie-parser@2.7.1: {}
|
set-cookie-parser@2.7.1: {}
|
||||||
|
|
||||||
|
siginfo@2.0.0: {}
|
||||||
|
|
||||||
sirv@3.0.1:
|
sirv@3.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@polka/url': 1.0.0-next.29
|
'@polka/url': 1.0.0-next.29
|
||||||
@@ -1453,6 +1662,10 @@ snapshots:
|
|||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
stackback@0.0.2: {}
|
||||||
|
|
||||||
|
std-env@3.9.0: {}
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0: {}
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
svelte-check@4.1.7(picomatch@4.0.2)(svelte@5.28.2)(typescript@5.8.3):
|
svelte-check@4.1.7(picomatch@4.0.2)(svelte@5.28.2)(typescript@5.8.3):
|
||||||
@@ -1499,17 +1712,48 @@ snapshots:
|
|||||||
mkdirp: 3.0.1
|
mkdirp: 3.0.1
|
||||||
yallist: 5.0.0
|
yallist: 5.0.0
|
||||||
|
|
||||||
|
tinybench@2.9.0: {}
|
||||||
|
|
||||||
|
tinyexec@0.3.2: {}
|
||||||
|
|
||||||
tinyglobby@0.2.13:
|
tinyglobby@0.2.13:
|
||||||
dependencies:
|
dependencies:
|
||||||
fdir: 6.4.4(picomatch@4.0.2)
|
fdir: 6.4.4(picomatch@4.0.2)
|
||||||
picomatch: 4.0.2
|
picomatch: 4.0.2
|
||||||
|
|
||||||
|
tinypool@1.1.0: {}
|
||||||
|
|
||||||
|
tinyrainbow@2.0.0: {}
|
||||||
|
|
||||||
|
tinyspy@3.0.2: {}
|
||||||
|
|
||||||
totalist@3.0.1: {}
|
totalist@3.0.1: {}
|
||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
typescript@5.8.3: {}
|
typescript@5.8.3: {}
|
||||||
|
|
||||||
|
vite-node@3.1.4(jiti@2.4.2)(lightningcss@1.29.2):
|
||||||
|
dependencies:
|
||||||
|
cac: 6.7.14
|
||||||
|
debug: 4.4.0
|
||||||
|
es-module-lexer: 1.7.0
|
||||||
|
pathe: 2.0.3
|
||||||
|
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/node'
|
||||||
|
- jiti
|
||||||
|
- less
|
||||||
|
- lightningcss
|
||||||
|
- sass
|
||||||
|
- sass-embedded
|
||||||
|
- stylus
|
||||||
|
- sugarss
|
||||||
|
- supports-color
|
||||||
|
- terser
|
||||||
|
- tsx
|
||||||
|
- yaml
|
||||||
|
|
||||||
vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2):
|
vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.4
|
esbuild: 0.25.4
|
||||||
@@ -1527,6 +1771,48 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||||
|
|
||||||
|
vitest@3.1.4(jiti@2.4.2)(lightningcss@1.29.2):
|
||||||
|
dependencies:
|
||||||
|
'@vitest/expect': 3.1.4
|
||||||
|
'@vitest/mocker': 3.1.4(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||||
|
'@vitest/pretty-format': 3.1.4
|
||||||
|
'@vitest/runner': 3.1.4
|
||||||
|
'@vitest/snapshot': 3.1.4
|
||||||
|
'@vitest/spy': 3.1.4
|
||||||
|
'@vitest/utils': 3.1.4
|
||||||
|
chai: 5.2.0
|
||||||
|
debug: 4.4.0
|
||||||
|
expect-type: 1.2.1
|
||||||
|
magic-string: 0.30.17
|
||||||
|
pathe: 2.0.3
|
||||||
|
std-env: 3.9.0
|
||||||
|
tinybench: 2.9.0
|
||||||
|
tinyexec: 0.3.2
|
||||||
|
tinyglobby: 0.2.13
|
||||||
|
tinypool: 1.1.0
|
||||||
|
tinyrainbow: 2.0.0
|
||||||
|
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||||
|
vite-node: 3.1.4(jiti@2.4.2)(lightningcss@1.29.2)
|
||||||
|
why-is-node-running: 2.3.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- jiti
|
||||||
|
- less
|
||||||
|
- lightningcss
|
||||||
|
- msw
|
||||||
|
- sass
|
||||||
|
- sass-embedded
|
||||||
|
- stylus
|
||||||
|
- sugarss
|
||||||
|
- supports-color
|
||||||
|
- terser
|
||||||
|
- tsx
|
||||||
|
- yaml
|
||||||
|
|
||||||
|
why-is-node-running@2.3.0:
|
||||||
|
dependencies:
|
||||||
|
siginfo: 2.0.0
|
||||||
|
stackback: 0.0.2
|
||||||
|
|
||||||
yallist@5.0.0: {}
|
yallist@5.0.0: {}
|
||||||
|
|
||||||
zimmerframe@1.1.2: {}
|
zimmerframe@1.1.2: {}
|
||||||
|
@@ -54,13 +54,7 @@ export async function checkImage(repo: GitRepo): Promise<boolean> {
|
|||||||
const URL = repo.html_url + IMAGE_URL_SUFFIX;
|
const URL = repo.html_url + IMAGE_URL_SUFFIX;
|
||||||
console.log("Checking image:", URL);
|
console.log("Checking image:", URL);
|
||||||
const response = await fetch(URL);
|
const response = await fetch(URL);
|
||||||
if (response.ok) {
|
return response.ok;
|
||||||
console.log("Image found!");
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
console.log("Image not found!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -9,13 +9,13 @@
|
|||||||
<slot name="headerLeft" class="text-2xl md:text-3xl truncate"></slot>
|
<slot name="headerLeft" class="text-2xl md:text-3xl truncate"></slot>
|
||||||
<slot name="headerRight" class="max-md:hidden text-xl md:text-2xl truncate"></slot>
|
<slot name="headerRight" class="max-md:hidden text-xl md:text-2xl truncate"></slot>
|
||||||
</div>
|
</div>
|
||||||
<hr class="mb-4 border-1" />
|
<hr class="border-1" />
|
||||||
<div class="flex-1 flex flex-col justify-center p-5">
|
<div class="flex-1 flex flex-col justify-center mt-4 mb-8">
|
||||||
<slot name="content"/>
|
<slot name="content"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-4 border-1" />
|
<hr class="border-1" />
|
||||||
<div class="flex flex-row justify-between items-center mt-2 text-base opacity-90">
|
<div class="flex flex-row justify-between items-center mt-4 text-base opacity-90">
|
||||||
<slot name="footerLeft"/>
|
<slot name="footerLeft"/>
|
||||||
<slot name="footerRight"/>
|
<slot name="footerRight"/>
|
||||||
</div>
|
</div>
|
||||||
|
33
src/lib/components/Collapsible.svelte
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let open = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="w-full">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex items-center justify-between w-full px-2 py-2 text-left rounded hover:font-bold transition group"
|
||||||
|
on:click={() => open = !open}
|
||||||
|
aria-expanded={open}
|
||||||
|
>
|
||||||
|
<span><slot name="label"/></span>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5 ml-2 transition-transform duration-200"
|
||||||
|
style="transform: rotate({open ? 90 : 0}deg)"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="overflow-hidden transition-all duration-300"
|
||||||
|
style="max-height: {open ? '1000px' : '0'}"
|
||||||
|
aria-hidden={!open}
|
||||||
|
>
|
||||||
|
<div class="pt-2">
|
||||||
|
<slot name="content"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -1,40 +1,28 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import Collapsible from "./Collapsible.svelte";
|
||||||
|
|
||||||
export let timelineData: Array<{
|
export let timelineData: Array<{
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
duration: string;
|
duration: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// Track open/closed state for each entry
|
|
||||||
let openStates = timelineData.map(() => false);
|
|
||||||
|
|
||||||
function toggle(index: number) {
|
|
||||||
openStates[index] = !openStates[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle(0); // Open the first entry by default
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col items-center justify-center">
|
<div class="flex flex-col items-center justify-center">
|
||||||
<div class="max-w-4xl w-full">
|
<div class="max-w-4xl w-full">
|
||||||
{#each timelineData as entry, i}
|
{#each timelineData as entry, i}
|
||||||
<div class="relative border-l border-gray-700 pl-8 pb-12">
|
<div class="relative border-l border-gray-700 pl-8 pb-12">
|
||||||
{#if openStates[i]}
|
{#if i == 0}
|
||||||
<div class="absolute top-0 left-[8px] text-green-400 w-4 h-4">♦</div>
|
<div class="absolute top-0 left-[8px] text-green-400 w-4 h-4">♦</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="absolute top-0 left-[8px] text-green-400 w-4 h-4">⋄</div>
|
<div class="absolute top-0 left-[8px] text-green-400 w-4 h-4">⋄</div>
|
||||||
{/if}
|
{/if}
|
||||||
<p class="text-sm opacity-70">{entry.duration}</p>
|
<p class="text-sm opacity-70">{entry.duration}</p>
|
||||||
<button
|
|
||||||
class="text-2lg font-semibold text-red-400 mt-1 focus:outline-none hover:underline transition"
|
<Collapsible open={i==0}>
|
||||||
on:click={() => toggle(i)}
|
<span slot="label" class="text-2lg font-semibold text-red-400 mt-1 focus:outline-none hover:underline transition">{entry.title}</span>
|
||||||
aria-expanded={openStates[i]}
|
<span slot="content">{@html entry.description}</span>
|
||||||
>
|
</Collapsible>
|
||||||
<h3 class="text-2lg font-semibold text-red-400 mt-1">{entry.title}</h3>
|
|
||||||
</button>
|
|
||||||
{#if openStates[i]}
|
|
||||||
<p class="mt-2 whitespace-pre-line transition-all duration-300">{@html entry.description}</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
export async function getJson(path: string) {
|
import type {ContentTemplate} from "$lib/types"
|
||||||
|
|
||||||
|
export async function getJson(path: string): Promise<ContentTemplate> {
|
||||||
let response = await fetch(path);
|
let response = await fetch(path);
|
||||||
let users = await response.json();
|
let users = await response.json();
|
||||||
return users;
|
return users;
|
||||||
|
0
src/lib/types.d.ts
vendored
@@ -1,10 +1,28 @@
|
|||||||
export type TimelinePosition = 'right' | 'left' | 'alternate';
|
export interface ContentTemplate {
|
||||||
|
name: string;
|
||||||
|
job_title: string;
|
||||||
|
location: string;
|
||||||
|
profile_photo: string;
|
||||||
|
about: string;
|
||||||
|
|
||||||
export type ParentPosition = 'right' | 'left';
|
skills: Skill[];
|
||||||
|
timeline: TimelineEvent[];
|
||||||
|
}
|
||||||
|
|
||||||
export type TimelineConfig = {
|
export interface Skill {
|
||||||
rootPosition: TimelinePosition;
|
name: string;
|
||||||
};
|
logo: string;
|
||||||
|
colour: string;
|
||||||
|
link: string;
|
||||||
|
about: string;
|
||||||
|
competency: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimelineEvent {
|
||||||
|
duration: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GitRepo {
|
export interface GitRepo {
|
||||||
name: string;
|
name: string;
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
import GridGallery from "$lib/components/GridGallery.svelte";
|
import GridGallery from "$lib/components/GridGallery.svelte";
|
||||||
import SkillProgress from "$lib/components/SkillProgress.svelte";
|
import SkillProgress from "$lib/components/SkillProgress.svelte";
|
||||||
import Timeline from '$lib/components/Timeline.svelte';
|
import Timeline from '$lib/components/Timeline.svelte';
|
||||||
|
import Collapsible from '$lib/components/Collapsible.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#await getJson('/json/me.json')}
|
{#await getJson('/json/me.json')}
|
||||||
@@ -24,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Card -->
|
<!-- Main Card -->
|
||||||
<Section label="[Experience]">
|
<Section label="[About]">
|
||||||
<Card>
|
<Card>
|
||||||
<h2 slot="headerLeft">{info.name}</h2>
|
<h2 slot="headerLeft">{info.name}</h2>
|
||||||
<h2 slot="headerRight">{info.job_title}</h2>
|
<h2 slot="headerRight">{info.job_title}</h2>
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
alt="Avatar"
|
alt="Avatar"
|
||||||
class="max-md:hidden rounded-full w-32 h-32 md:w-48 md:h-48 mt-2 mb-2 p-2 border-3"
|
class="max-md:hidden rounded-full w-32 h-32 md:w-48 md:h-48 mt-2 mb-2 p-2 border-3"
|
||||||
/>
|
/>
|
||||||
<p>{@html info.about}</p>
|
<p class="[&>*]:underline [&>*]:decoration-2 [&>*]:decoration-transparent [&>*]:hover:decoration-inherit [&>*]:transition-all [&>*]:duration-300 [&>*]:text-green-600">{@html info.about}</p>
|
||||||
</div>
|
</div>
|
||||||
<h3 slot="footerLeft">{@html info.location}</h3>
|
<h3 slot="footerLeft">{@html info.location}</h3>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -46,8 +47,12 @@
|
|||||||
{#each info.skills as skill}
|
{#each info.skills as skill}
|
||||||
<Card containerStyle="opacity-100 hover:opacity-100 hover:scale-[105%] md:opacity-70 transition-all duration-300">
|
<Card containerStyle="opacity-100 hover:opacity-100 hover:scale-[105%] md:opacity-70 transition-all duration-300">
|
||||||
<h2 slot="headerLeft">{skill.name}</h2>
|
<h2 slot="headerLeft">{skill.name}</h2>
|
||||||
|
<i slot="headerRight" class="text-slate-300 text-5xl {skill.logo}"></i>
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
{skill.about}
|
<Collapsible>
|
||||||
|
<span slot="label" class="text-lg">About {skill.name}</span>
|
||||||
|
<span slot="content">{skill.about}</span>
|
||||||
|
</Collapsible>
|
||||||
<SkillProgress skillColour={skill.colour} value={skill.competency} />
|
<SkillProgress skillColour={skill.colour} value={skill.competency} />
|
||||||
</div>
|
</div>
|
||||||
<h3 slot="footerLeft"><a href="{skill.link}" target="_blank">{skill.link}</a></h3>
|
<h3 slot="footerLeft"><a href="{skill.link}" target="_blank">{skill.link}</a></h3>
|
||||||
|
@@ -22,12 +22,12 @@
|
|||||||
"competency": 80
|
"competency": 80
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Tailwind CSS",
|
"name" : "Python",
|
||||||
"logo": "devicon-tailwindcss-plain",
|
"logo": "devicon-python-plain",
|
||||||
"colour": "bg-blue-800",
|
"colour": "bg-yellow-400",
|
||||||
"link": "https://tailwindcss.com/",
|
"link": "https://python.org",
|
||||||
"about": "Tailwind CSS is a utility-first CSS framework that enables rapid UI development with a focus on customization and responsiveness.",
|
"about": "Python is a versatile language known for its simplicity and readability, making it ideal for rapid development and data analysis.",
|
||||||
"competency": 60
|
"competency": 70
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Git",
|
"name": "Git",
|
||||||
@@ -45,6 +45,54 @@
|
|||||||
"about": "Docker simplifies deployment by packaging applications in lightweight containers, ensuring consistency across environments.",
|
"about": "Docker simplifies deployment by packaging applications in lightweight containers, ensuring consistency across environments.",
|
||||||
"competency": 100
|
"competency": 100
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Kubernetes",
|
||||||
|
"logo": "devicon-kubernetes-plain",
|
||||||
|
"colour": "bg-blue-600",
|
||||||
|
"link": "https://kubernetes.io",
|
||||||
|
"about": "Kubernetes automates the deployment, scaling, and management of containerized applications, enhancing operational efficiency.",
|
||||||
|
"competency": 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PostgreSQL",
|
||||||
|
"logo": "devicon-postgresql-plain",
|
||||||
|
"colour": "bg-blue-700",
|
||||||
|
"link": "https://postgresql.org",
|
||||||
|
"about": "PostgreSQL is a powerful, open-source relational database known for its robustness and advanced features.",
|
||||||
|
"competency": 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MongoDB",
|
||||||
|
"logo": "devicon-mongodb-plain",
|
||||||
|
"colour": "bg-green-500",
|
||||||
|
"link": "https://mongodb.com",
|
||||||
|
"about": "MongoDB is a NoSQL database that provides flexibility and scalability for modern applications with unstructured data.",
|
||||||
|
"competency": 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Redis",
|
||||||
|
"logo": "devicon-redis-plain",
|
||||||
|
"colour": "bg-red-600",
|
||||||
|
"link": "https://redis.io",
|
||||||
|
"about": "Redis is an in-memory data structure store, used as a database, cache, and message broker for high-performance applications.",
|
||||||
|
"competency": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "JavaScript",
|
||||||
|
"logo": "devicon-javascript-plain",
|
||||||
|
"colour": "bg-yellow-500",
|
||||||
|
"link": "https://javascript.com",
|
||||||
|
"about": "JavaScript is a versatile language that powers dynamic web applications and enhances user interactivity.",
|
||||||
|
"competency": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tailwind CSS",
|
||||||
|
"logo": "devicon-tailwindcss-plain",
|
||||||
|
"colour": "bg-blue-800",
|
||||||
|
"link": "https://tailwindcss.com/",
|
||||||
|
"about": "Tailwind CSS is a utility-first CSS framework that enables rapid UI development with a focus on customization and responsiveness.",
|
||||||
|
"competency": 60
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Svelte",
|
"name": "Svelte",
|
||||||
"logo": "devicon-svelte-plain",
|
"logo": "devicon-svelte-plain",
|
||||||
@@ -56,9 +104,14 @@
|
|||||||
],
|
],
|
||||||
"timeline" : [
|
"timeline" : [
|
||||||
{
|
{
|
||||||
"duration" : "September 2022 - Present",
|
"duration" : "April 2025 - Present",
|
||||||
"title" : "Thales UK - Software Engineer",
|
"title" : "Thales UK (DDCC) - Software Engineer",
|
||||||
"description" : "As a software engineering apprentice at Thales UK, I find myself partaking in agile / scrum development methodologies in a strong team of 6 other engineers. The team iterates on a pre-existing system designed for the MOD, written in C++, using internal frameworks to assist."
|
"description" : "As a 3rd year apprentice at Thales UK’s Digital Data Competency Centre, I have taken on responsibility for developing microservices that encapsulate Machine Learning models provided by R&D teams, helping to advance product readiness. These services are primarily written in Python and deployed to Kubernetes clusters for use across the business. Our team also designs and maintains CI/CD pipelines to automate the deployment of both these services and their supporting infrastructure."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration" : "September 2022 - April 2025",
|
||||||
|
"title" : "Thales UK (ISR) - Software Engineer",
|
||||||
|
"description" : "As a software engineering apprentice at Thales UK, Intelligence Surveillance and Reconnaissance, I worked within an agile team of six engineers, contributing to the ongoing development of a C++ system for the MOD. My role involved collaborating closely with colleagues, following Scrum methodologies, and leveraging internal frameworks to enhance and maintain the existing platform."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"duration" : "September 2022 - Present",
|
"duration" : "September 2022 - Present",
|
||||||
|
28
tests/git.svelte.test.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { expect, test } from 'vitest';
|
||||||
|
import { fetchRepos, timeSince, checkImage } from '$lib/api/git';
|
||||||
|
|
||||||
|
test('Fetch Repos', async () => {
|
||||||
|
let repos = await fetchRepos();
|
||||||
|
expect(repos.length).toEqual(12);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([
|
||||||
|
[new Date((Date.now() - 1000 * 60 * 60 * 24)), 'Yesterday'],
|
||||||
|
[new Date((Date.now() - 1000 * 60 * 60 * 24 * 2)), '2 days ago'],
|
||||||
|
[new Date((Date.now() - 1000 * 60 * 60 * 24 * 7)), '1 week ago'],
|
||||||
|
[new Date((Date.now() - 1000 * 60 * 60 * 24 * 7 * 2)), '2 weeks ago'],
|
||||||
|
[new Date((Date.now() - 1000 * 60 * 60 * 24 * 30)), '1 month ago'],
|
||||||
|
[new Date((Date.now() - 1000 * 60 * 60 * 24 * 365)), '1 year ago'],
|
||||||
|
])('', (time, expected) => {
|
||||||
|
expect(timeSince(time)).toBe(expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test('Check Image', async () => {
|
||||||
|
let repos = await fetchRepos();
|
||||||
|
|
||||||
|
for (let repo of repos) {
|
||||||
|
let image = await checkImage(repo);
|
||||||
|
expect(image).toBeDefined();
|
||||||
|
}
|
||||||
|
});
|
@@ -3,8 +3,5 @@ import { defineConfig } from 'vite';
|
|||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [tailwindcss(), sveltekit()],
|
||||||
tailwindcss(),
|
|
||||||
sveltekit(),
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|