Merge pull request 'chore/tailwind-conversion' (#32) from chore/tailwind-conversion into development
All checks were successful
Build and Push Development Docker Image / build-and-push (push) Successful in 1m36s
All checks were successful
Build and Push Development Docker Image / build-and-push (push) Successful in 1m36s
Reviewed-on: #32
This commit is contained in:
commit
79f6e8e90b
@ -1,5 +1,6 @@
|
||||
{
|
||||
"useTabs": true,
|
||||
"useTabs": false,
|
||||
"tabWidth": 4,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
|
@ -26,5 +26,10 @@
|
||||
"typescript": "5.8.3",
|
||||
"vite": "6.3.5"
|
||||
},
|
||||
"type": "module"
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.6",
|
||||
"svelte-toasts": "^1.1.2",
|
||||
"tailwindcss": "^4.1.6"
|
||||
}
|
||||
}
|
||||
|
422
pnpm-lock.yaml
generated
422
pnpm-lock.yaml
generated
@ -7,22 +7,32 @@ settings:
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.1.6
|
||||
version: 4.1.6(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
svelte-toasts:
|
||||
specifier: ^1.1.2
|
||||
version: 1.1.2
|
||||
tailwindcss:
|
||||
specifier: ^4.1.6
|
||||
version: 4.1.6
|
||||
devDependencies:
|
||||
'@rollup/plugin-json':
|
||||
specifier: ^6.0.0
|
||||
version: 6.1.0(rollup@4.40.2)
|
||||
'@sveltejs/adapter-auto':
|
||||
specifier: 6.0.0
|
||||
version: 6.0.0(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5))
|
||||
version: 6.0.0(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))
|
||||
'@sveltejs/adapter-node':
|
||||
specifier: 5.2.12
|
||||
version: 5.2.12(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5))
|
||||
version: 5.2.12(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))
|
||||
'@sveltejs/kit':
|
||||
specifier: 2.20.8
|
||||
version: 2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5)
|
||||
version: 2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
'@sveltejs/vite-plugin-svelte':
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.3(svelte@5.28.2)(vite@6.3.5)
|
||||
version: 5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
prettier:
|
||||
specifier: 3.5.3
|
||||
version: 3.5.3
|
||||
@ -43,7 +53,7 @@ importers:
|
||||
version: 5.8.3
|
||||
vite:
|
||||
specifier: 6.3.5
|
||||
version: 6.3.5
|
||||
version: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||
|
||||
packages:
|
||||
|
||||
@ -201,6 +211,10 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@isaacs/fs-minipass@4.0.1':
|
||||
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.8':
|
||||
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@ -397,6 +411,96 @@ packages:
|
||||
svelte: ^5.0.0
|
||||
vite: ^6.0.0
|
||||
|
||||
'@tailwindcss/node@4.1.6':
|
||||
resolution: {integrity: sha512-ed6zQbgmKsjsVvodAS1q1Ld2BolEuxJOSyyNc+vhkjdmfNUDCmQnlXBfQkHrlzNmslxHsQU/bFmzcEbv4xXsLg==}
|
||||
|
||||
'@tailwindcss/oxide-android-arm64@4.1.6':
|
||||
resolution: {integrity: sha512-VHwwPiwXtdIvOvqT/0/FLH/pizTVu78FOnI9jQo64kSAikFSZT7K4pjyzoDpSMaveJTGyAKvDjuhxJxKfmvjiQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@tailwindcss/oxide-darwin-arm64@4.1.6':
|
||||
resolution: {integrity: sha512-weINOCcqv1HVBIGptNrk7c6lWgSFFiQMcCpKM4tnVi5x8OY2v1FrV76jwLukfT6pL1hyajc06tyVmZFYXoxvhQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@tailwindcss/oxide-darwin-x64@4.1.6':
|
||||
resolution: {integrity: sha512-3FzekhHG0ww1zQjQ1lPoq0wPrAIVXAbUkWdWM8u5BnYFZgb9ja5ejBqyTgjpo5mfy0hFOoMnMuVDI+7CXhXZaQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@tailwindcss/oxide-freebsd-x64@4.1.6':
|
||||
resolution: {integrity: sha512-4m5F5lpkBZhVQJq53oe5XgJ+aFYWdrgkMwViHjRsES3KEu2m1udR21B1I77RUqie0ZYNscFzY1v9aDssMBZ/1w==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.6':
|
||||
resolution: {integrity: sha512-qU0rHnA9P/ZoaDKouU1oGPxPWzDKtIfX7eOGi5jOWJKdxieUJdVV+CxWZOpDWlYTd4N3sFQvcnVLJWJ1cLP5TA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.1.6':
|
||||
resolution: {integrity: sha512-jXy3TSTrbfgyd3UxPQeXC3wm8DAgmigzar99Km9Sf6L2OFfn/k+u3VqmpgHQw5QNfCpPe43em6Q7V76Wx7ogIQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.6':
|
||||
resolution: {integrity: sha512-8kjivE5xW0qAQ9HX9reVFmZj3t+VmljDLVRJpVBEoTR+3bKMnvC7iLcoSGNIUJGOZy1mLVq7x/gerVg0T+IsYw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.6':
|
||||
resolution: {integrity: sha512-A4spQhwnWVpjWDLXnOW9PSinO2PTKJQNRmL/aIl2U/O+RARls8doDfs6R41+DAXK0ccacvRyDpR46aVQJJCoCg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.6':
|
||||
resolution: {integrity: sha512-YRee+6ZqdzgiQAHVSLfl3RYmqeeaWVCk796MhXhLQu2kJu2COHBkqlqsqKYx3p8Hmk5pGCQd2jTAoMWWFeyG2A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.6':
|
||||
resolution: {integrity: sha512-qAp4ooTYrBQ5pk5jgg54/U1rCJ/9FLYOkkQ/nTE+bVMseMfB6O7J8zb19YTpWuu4UdfRf5zzOrNKfl6T64MNrQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
bundledDependencies:
|
||||
- '@napi-rs/wasm-runtime'
|
||||
- '@emnapi/core'
|
||||
- '@emnapi/runtime'
|
||||
- '@tybys/wasm-util'
|
||||
- '@emnapi/wasi-threads'
|
||||
- tslib
|
||||
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.1.6':
|
||||
resolution: {integrity: sha512-nqpDWk0Xr8ELO/nfRUDjk1pc9wDJ3ObeDdNMHLaymc4PJBWj11gdPCWZFKSK2AVKjJQC7J2EfmSmf47GN7OuLg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.1.6':
|
||||
resolution: {integrity: sha512-5k9xF33xkfKpo9wCvYcegQ21VwIBU1/qEbYlVukfEIyQbEA47uK8AAwS7NVjNE3vHzcmxMYwd0l6L4pPjjm1rQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tailwindcss/oxide@4.1.6':
|
||||
resolution: {integrity: sha512-0bpEBQiGx+227fW4G0fLQ8vuvyy5rsB1YIYNapTq3aRsJ9taF3f5cCaovDjN5pUGKKzcpMrZst/mhNaKAPOHOA==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@tailwindcss/vite@4.1.6':
|
||||
resolution: {integrity: sha512-zjtqjDeY1w3g2beYQtrMAf51n5G7o+UwmyOjtsDMP7t6XyoRMOidcoKP32ps7AkNOHIXEOK0bhIC05dj8oJp4w==}
|
||||
peerDependencies:
|
||||
vite: ^5.2.0 || ^6
|
||||
|
||||
'@types/cookie@0.6.0':
|
||||
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||
|
||||
@ -423,6 +527,10 @@ packages:
|
||||
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
||||
engines: {node: '>= 14.16.0'}
|
||||
|
||||
chownr@3.0.0:
|
||||
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
clsx@2.1.1:
|
||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||
engines: {node: '>=6'}
|
||||
@ -447,9 +555,17 @@ packages:
|
||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
detect-libc@2.0.4:
|
||||
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
devalue@5.1.1:
|
||||
resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==}
|
||||
|
||||
enhanced-resolve@5.18.1:
|
||||
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
esbuild@0.25.4:
|
||||
resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
|
||||
engines: {node: '>=18'}
|
||||
@ -480,6 +596,9 @@ packages:
|
||||
function-bind@1.1.2:
|
||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||
|
||||
graceful-fs@4.2.11:
|
||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||
|
||||
hasown@2.0.2:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -500,16 +619,97 @@ packages:
|
||||
is-reference@3.0.3:
|
||||
resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
|
||||
|
||||
jiti@2.4.2:
|
||||
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
|
||||
hasBin: true
|
||||
|
||||
kleur@4.1.5:
|
||||
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
lightningcss-darwin-arm64@1.29.2:
|
||||
resolution: {integrity: sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-darwin-x64@1.29.2:
|
||||
resolution: {integrity: sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-freebsd-x64@1.29.2:
|
||||
resolution: {integrity: sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.29.2:
|
||||
resolution: {integrity: sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.29.2:
|
||||
resolution: {integrity: sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.29.2:
|
||||
resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.29.2:
|
||||
resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-musl@1.29.2:
|
||||
resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.29.2:
|
||||
resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss-win32-x64-msvc@1.29.2:
|
||||
resolution: {integrity: sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss@1.29.2:
|
||||
resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
locate-character@3.0.0:
|
||||
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
|
||||
|
||||
magic-string@0.30.17:
|
||||
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
||||
|
||||
minipass@7.1.2:
|
||||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minizlib@3.0.2:
|
||||
resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
mkdirp@3.0.1:
|
||||
resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
mri@1.2.0:
|
||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||
engines: {node: '>=4'}
|
||||
@ -592,10 +792,24 @@ packages:
|
||||
svelte: ^4.0.0 || ^5.0.0-next.0
|
||||
typescript: '>=5.0.0'
|
||||
|
||||
svelte-toasts@1.1.2:
|
||||
resolution: {integrity: sha512-m+yL4eEKXyJoyjTYaH1j1GFwF0Pi8YDqnVfwWPDmwi4712iZesv+TNCmToSNlav3R5Vkmc8ZBRkT8DOcu3sywQ==}
|
||||
|
||||
svelte@5.28.2:
|
||||
resolution: {integrity: sha512-FbWBxgWOpQfhKvoGJv/TFwzqb4EhJbwCD17dB0tEpQiw1XyUEKZJtgm4nA4xq3LLsMo7hu5UY/BOFmroAxKTMg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
tailwindcss@4.1.6:
|
||||
resolution: {integrity: sha512-j0cGLTreM6u4OWzBeLBpycK0WIh8w7kSwcUsQZoGLHZ7xDTdM69lN64AgoIEEwFi0tnhs4wSykUa5YWxAzgFYg==}
|
||||
|
||||
tapable@2.2.1:
|
||||
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tar@7.4.3:
|
||||
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
tinyglobby@0.2.13:
|
||||
resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@ -660,6 +874,10 @@ packages:
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
yallist@5.0.0:
|
||||
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
zimmerframe@1.1.2:
|
||||
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
|
||||
|
||||
@ -745,6 +963,10 @@ snapshots:
|
||||
'@esbuild/win32-x64@0.25.4':
|
||||
optional: true
|
||||
|
||||
'@isaacs/fs-minipass@4.0.1':
|
||||
dependencies:
|
||||
minipass: 7.1.2
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.8':
|
||||
dependencies:
|
||||
'@jridgewell/set-array': 1.2.1
|
||||
@ -864,22 +1086,22 @@ snapshots:
|
||||
dependencies:
|
||||
acorn: 8.14.1
|
||||
|
||||
'@sveltejs/adapter-auto@6.0.0(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5))':
|
||||
'@sveltejs/adapter-auto@6.0.0(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))':
|
||||
dependencies:
|
||||
'@sveltejs/kit': 2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5)
|
||||
'@sveltejs/kit': 2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
import-meta-resolve: 4.1.0
|
||||
|
||||
'@sveltejs/adapter-node@5.2.12(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5))':
|
||||
'@sveltejs/adapter-node@5.2.12(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))':
|
||||
dependencies:
|
||||
'@rollup/plugin-commonjs': 28.0.3(rollup@4.40.2)
|
||||
'@rollup/plugin-json': 6.1.0(rollup@4.40.2)
|
||||
'@rollup/plugin-node-resolve': 16.0.1(rollup@4.40.2)
|
||||
'@sveltejs/kit': 2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5)
|
||||
'@sveltejs/kit': 2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
rollup: 4.40.2
|
||||
|
||||
'@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5)':
|
||||
'@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))':
|
||||
dependencies:
|
||||
'@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.28.2)(vite@6.3.5)
|
||||
'@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
'@types/cookie': 0.6.0
|
||||
cookie: 0.6.0
|
||||
devalue: 5.1.1
|
||||
@ -892,30 +1114,101 @@ snapshots:
|
||||
set-cookie-parser: 2.7.1
|
||||
sirv: 3.0.1
|
||||
svelte: 5.28.2
|
||||
vite: 6.3.5
|
||||
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||
|
||||
'@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5)':
|
||||
'@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))':
|
||||
dependencies:
|
||||
'@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.28.2)(vite@6.3.5)
|
||||
'@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
debug: 4.4.0
|
||||
svelte: 5.28.2
|
||||
vite: 6.3.5
|
||||
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5)':
|
||||
'@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))':
|
||||
dependencies:
|
||||
'@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5))(svelte@5.28.2)(vite@6.3.5)
|
||||
'@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.28.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
debug: 4.4.0
|
||||
deepmerge: 4.3.1
|
||||
kleur: 4.1.5
|
||||
magic-string: 0.30.17
|
||||
svelte: 5.28.2
|
||||
vite: 6.3.5
|
||||
vitefu: 1.0.6(vite@6.3.5)
|
||||
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||
vitefu: 1.0.6(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@tailwindcss/node@4.1.6':
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
enhanced-resolve: 5.18.1
|
||||
jiti: 2.4.2
|
||||
lightningcss: 1.29.2
|
||||
magic-string: 0.30.17
|
||||
source-map-js: 1.2.1
|
||||
tailwindcss: 4.1.6
|
||||
|
||||
'@tailwindcss/oxide-android-arm64@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-darwin-arm64@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-darwin-x64@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-freebsd-x64@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.1.6':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide@4.1.6':
|
||||
dependencies:
|
||||
detect-libc: 2.0.4
|
||||
tar: 7.4.3
|
||||
optionalDependencies:
|
||||
'@tailwindcss/oxide-android-arm64': 4.1.6
|
||||
'@tailwindcss/oxide-darwin-arm64': 4.1.6
|
||||
'@tailwindcss/oxide-darwin-x64': 4.1.6
|
||||
'@tailwindcss/oxide-freebsd-x64': 4.1.6
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.6
|
||||
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.6
|
||||
'@tailwindcss/oxide-linux-arm64-musl': 4.1.6
|
||||
'@tailwindcss/oxide-linux-x64-gnu': 4.1.6
|
||||
'@tailwindcss/oxide-linux-x64-musl': 4.1.6
|
||||
'@tailwindcss/oxide-wasm32-wasi': 4.1.6
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.6
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.1.6
|
||||
|
||||
'@tailwindcss/vite@4.1.6(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.1.6
|
||||
'@tailwindcss/oxide': 4.1.6
|
||||
tailwindcss: 4.1.6
|
||||
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||
|
||||
'@types/cookie@0.6.0': {}
|
||||
|
||||
'@types/estree@1.0.7': {}
|
||||
@ -932,6 +1225,8 @@ snapshots:
|
||||
dependencies:
|
||||
readdirp: 4.1.2
|
||||
|
||||
chownr@3.0.0: {}
|
||||
|
||||
clsx@2.1.1: {}
|
||||
|
||||
commondir@1.0.1: {}
|
||||
@ -944,8 +1239,15 @@ snapshots:
|
||||
|
||||
deepmerge@4.3.1: {}
|
||||
|
||||
detect-libc@2.0.4: {}
|
||||
|
||||
devalue@5.1.1: {}
|
||||
|
||||
enhanced-resolve@5.18.1:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
tapable: 2.2.1
|
||||
|
||||
esbuild@0.25.4:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.25.4
|
||||
@ -991,6 +1293,8 @@ snapshots:
|
||||
|
||||
function-bind@1.1.2: {}
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
||||
hasown@2.0.2:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
@ -1011,14 +1315,69 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.7
|
||||
|
||||
jiti@2.4.2: {}
|
||||
|
||||
kleur@4.1.5: {}
|
||||
|
||||
lightningcss-darwin-arm64@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-x64@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-freebsd-x64@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-musl@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-gnu@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-musl@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-x64-msvc@1.29.2:
|
||||
optional: true
|
||||
|
||||
lightningcss@1.29.2:
|
||||
dependencies:
|
||||
detect-libc: 2.0.4
|
||||
optionalDependencies:
|
||||
lightningcss-darwin-arm64: 1.29.2
|
||||
lightningcss-darwin-x64: 1.29.2
|
||||
lightningcss-freebsd-x64: 1.29.2
|
||||
lightningcss-linux-arm-gnueabihf: 1.29.2
|
||||
lightningcss-linux-arm64-gnu: 1.29.2
|
||||
lightningcss-linux-arm64-musl: 1.29.2
|
||||
lightningcss-linux-x64-gnu: 1.29.2
|
||||
lightningcss-linux-x64-musl: 1.29.2
|
||||
lightningcss-win32-arm64-msvc: 1.29.2
|
||||
lightningcss-win32-x64-msvc: 1.29.2
|
||||
|
||||
locate-character@3.0.0: {}
|
||||
|
||||
magic-string@0.30.17:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
|
||||
minipass@7.1.2: {}
|
||||
|
||||
minizlib@3.0.2:
|
||||
dependencies:
|
||||
minipass: 7.1.2
|
||||
|
||||
mkdirp@3.0.1: {}
|
||||
|
||||
mri@1.2.0: {}
|
||||
|
||||
mrmime@2.0.1: {}
|
||||
@ -1108,6 +1467,8 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- picomatch
|
||||
|
||||
svelte-toasts@1.1.2: {}
|
||||
|
||||
svelte@5.28.2:
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
@ -1125,6 +1486,19 @@ snapshots:
|
||||
magic-string: 0.30.17
|
||||
zimmerframe: 1.1.2
|
||||
|
||||
tailwindcss@4.1.6: {}
|
||||
|
||||
tapable@2.2.1: {}
|
||||
|
||||
tar@7.4.3:
|
||||
dependencies:
|
||||
'@isaacs/fs-minipass': 4.0.1
|
||||
chownr: 3.0.0
|
||||
minipass: 7.1.2
|
||||
minizlib: 3.0.2
|
||||
mkdirp: 3.0.1
|
||||
yallist: 5.0.0
|
||||
|
||||
tinyglobby@0.2.13:
|
||||
dependencies:
|
||||
fdir: 6.4.4(picomatch@4.0.2)
|
||||
@ -1136,7 +1510,7 @@ snapshots:
|
||||
|
||||
typescript@5.8.3: {}
|
||||
|
||||
vite@6.3.5:
|
||||
vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2):
|
||||
dependencies:
|
||||
esbuild: 0.25.4
|
||||
fdir: 6.4.4(picomatch@4.0.2)
|
||||
@ -1146,9 +1520,13 @@ snapshots:
|
||||
tinyglobby: 0.2.13
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.4.2
|
||||
lightningcss: 1.29.2
|
||||
|
||||
vitefu@1.0.6(vite@6.3.5):
|
||||
vitefu@1.0.6(vite@6.3.5(jiti@2.4.2)(lightningcss@1.29.2)):
|
||||
optionalDependencies:
|
||||
vite: 6.3.5
|
||||
vite: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
|
||||
|
||||
yallist@5.0.0: {}
|
||||
|
||||
zimmerframe@1.1.2: {}
|
||||
|
1
src/app.css
Normal file
1
src/app.css
Normal file
@ -0,0 +1 @@
|
||||
@import "tailwindcss"
|
154
src/app.html
154
src/app.html
@ -1,133 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="Luke Else - Software Developer at Thales UK. I specialise in developing distributed systems in C++ using highly scalable internal frameworks. I also develop backend and system applications in my spare time using both Svelte, Rust and C++. Feel free to check my work out at https://git.luke-else.co.uk." />
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Luke Else - Software Developer at Thales UK. I specialise in developing distributed systems in C++ using highly scalable internal frameworks. I also develop backend and system applications in my spare time using both Svelte, Rust and C++. Feel free to check my work out at https://git.luke-else.co.uk."
|
||||
/>
|
||||
<meta name="author" content="Luke Else (mail@luke-else.co.uk)" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.15.1/devicon.min.css">
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<script async src="https://tracking.luke-else.co.uk/tracker.js" data-ackee-server="https://tracking.luke-else.co.uk" data-ackee-domain-id="6c59ab88-dc6d-4d53-9831-0d6bff919dcd" data-ackee-opts='{ "detailed": true }'></script>
|
||||
%sveltekit.head%
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.15.1/devicon.min.css"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<script
|
||||
async
|
||||
src="https://tracking.luke-else.co.uk/tracker.js"
|
||||
data-ackee-server="https://tracking.luke-else.co.uk"
|
||||
data-ackee-domain-id="6c59ab88-dc6d-4d53-9831-0d6bff919dcd"
|
||||
data-ackee-opts='{ "detailed": true }'
|
||||
></script>
|
||||
%sveltekit.head%
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--font: Consolas, 'Cascadia Code', Monaco, 'SF Mono', 'DejaVu Sans Mono', 'Roboto Mono';
|
||||
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font);
|
||||
font-size: 110%;
|
||||
margin: 2rem;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
color: var(--header);
|
||||
border: 0;
|
||||
}
|
||||
<style></style>
|
||||
</head>
|
||||
|
||||
hr {
|
||||
border: .12em solid var(--accent);
|
||||
border-radius: 5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar,
|
||||
*::-webkit-scrollbar-thumb {
|
||||
width: 26px;
|
||||
border-radius: 13px;
|
||||
background-clip: padding-box;
|
||||
border: 10px solid transparent;
|
||||
color: var(--fg);
|
||||
}
|
||||
*::-webkit-scrollbar-thumb:hover{
|
||||
color: var(--link);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
box-shadow: inset 0 0 0 10px;
|
||||
}
|
||||
|
||||
@media (max-width:600px) {
|
||||
.not-required {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
color: var(--link);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
a:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 0%;
|
||||
border-bottom: 2px solid var(--fg);
|
||||
transition: 0.4s;
|
||||
}
|
||||
|
||||
a:hover:after {
|
||||
width: 100%;
|
||||
color: var(--glow);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--glow);
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: var(--header);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 90%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
gap: 3em 3em;
|
||||
padding: 2em 0em 2em 0em;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
@keyframes animationName {
|
||||
0% { opacity:0; }
|
||||
50% { opacity:1; }
|
||||
100% { opacity:0; }
|
||||
}
|
||||
@-o-keyframes animationName{
|
||||
0% { opacity:0; }
|
||||
50% { opacity:1; }
|
||||
100% { opacity:0; }
|
||||
}
|
||||
@-moz-keyframes animationName{
|
||||
0% { opacity:0; }
|
||||
50% { opacity:1; }
|
||||
100% { opacity:0; }
|
||||
}
|
||||
@-webkit-keyframes animationName{
|
||||
0% { opacity:0; }
|
||||
50% { opacity:1; }
|
||||
100% { opacity:0; }
|
||||
}
|
||||
.elementToFadeInAndOut {
|
||||
-webkit-animation: animationName 1.5s infinite;
|
||||
-moz-animation: animationName 1.5s infinite;
|
||||
-o-animation: animationName 1.5s infinite;
|
||||
animation: animationName 1.5s infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,69 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
export let headerLeft: string = "";
|
||||
export let headerRight: string = "";
|
||||
export let headerColour: string = "text-red-500";
|
||||
export let footer: string = "";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function onClick() {
|
||||
dispatch('click');
|
||||
}
|
||||
// Allows additional styling to be applied to the Card component's outer wrapping
|
||||
export let containerStyle: string = "";
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
flex: 2 1 15em;
|
||||
padding: .5em 2.5em 2em 2.5em;
|
||||
background: var(--bg-secondary);
|
||||
border-radius: .5em;
|
||||
scroll-snap-align: start;
|
||||
transition: all 0.2s;
|
||||
box-shadow: .25em .25em .5em var(--hover);
|
||||
}
|
||||
|
||||
.card:hover, .card:focus-within {
|
||||
box-shadow: .5em .5em .5em var(--hover);
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.card .card-header :global(div) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card .card-content :global(div) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.card .card-footer :global(div){
|
||||
margin-bottom: 1em;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
max-width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="card" on:click={onClick}>
|
||||
<div class="card-header">
|
||||
<slot name="header"></slot>
|
||||
<div class={containerStyle}>
|
||||
<div class="bg-slate-100/10 dark:bg-slate-100/10 rounded-2xl shadow-2xl p-6 flex flex-col h-full w-full">
|
||||
<div class="{headerColour} flex flex-row justify-between items-center mb-4">
|
||||
<p class="text-2xl md:text-3xl font-bold truncate">{headerLeft}</p>
|
||||
|
||||
{#if headerRight}
|
||||
<p class="max-md:hidden text-xl md:text-2xl truncate">{@html headerRight}</p>
|
||||
{/if}
|
||||
</div>
|
||||
<hr class="mb-4 border-1" />
|
||||
<div class="flex-1 flex flex-col justify-center p-5">
|
||||
<slot />
|
||||
</div>
|
||||
{#if footer}
|
||||
<hr class="my-4 border-1" />
|
||||
<div class="mt-2 text-base opacity-90">
|
||||
{@html footer}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<hr />
|
||||
<div class="card-content">
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
<hr class="not-required"/>
|
||||
<div class="card-footer">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,102 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function onClick() {
|
||||
dispatch('click');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.sliding-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
flex: 2 1 15em;
|
||||
padding: 0.5em 2.5em 2em 2.5em;
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 0.5em;
|
||||
scroll-snap-align: start;
|
||||
transition: all 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sliding-card:hover {
|
||||
box-shadow: .5em .5em .5em var(--hover);
|
||||
}
|
||||
|
||||
.sliding-card .sliding-card-header :global(div) {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden; /* Ensure smooth sliding */
|
||||
}
|
||||
|
||||
.sliding-card-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 100%;
|
||||
flex-grow: 1;
|
||||
z-index: 1; /* Keep it below the sliding content */
|
||||
}
|
||||
|
||||
.sliding-content {
|
||||
position: absolute; /* Now it sits on top */
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%; /* Cover entire content */
|
||||
background: var(--bg-secondary);
|
||||
transform: translateY(100%); /* Start hidden */
|
||||
transition: transform 0.3s ease-in-out;
|
||||
z-index: 2; /* Now above main content */
|
||||
}
|
||||
|
||||
.sliding-card:hover .sliding-content {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.sliding-card .sliding-card-footer :global(div){
|
||||
margin-bottom: 1em;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
max-width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="sliding-card" on:click={onClick}>
|
||||
<div class="sliding-card-header">
|
||||
<slot name="header"></slot>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<!-- Wrapper to stack sliding-card-content and sliding-content -->
|
||||
<div class="content-wrapper">
|
||||
<div class="sliding-card-content">
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
<div class="sliding-content">
|
||||
<slot name="sliding-content"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="not-required"/>
|
||||
<div class="sliding-card-footer">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
7
src/lib/components/FlexGallery.svelte
Normal file
7
src/lib/components/FlexGallery.svelte
Normal file
@ -0,0 +1,7 @@
|
||||
<script lang="ts">
|
||||
</script>
|
||||
|
||||
<!-- FlexGallery.svelte -->
|
||||
<div class="flex flex-wrap gap-10 w-full">
|
||||
<slot />
|
||||
</div>
|
@ -1,82 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let showModal: boolean;
|
||||
|
||||
let dialog: HTMLDialogElement;
|
||||
|
||||
$: if (dialog && showModal) dialog.showModal();
|
||||
|
||||
import CloseIcon from "./Toasts/CloseIcon.svelte";
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events a11y-no-noninteractive-element-interactions -->
|
||||
<dialog
|
||||
bind:this={dialog}
|
||||
on:close={() => (showModal = false)}
|
||||
on:click|self={() => dialog.close()}
|
||||
>
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div on:click|stopPropagation>
|
||||
<slot name="header" />
|
||||
<hr />
|
||||
<slot />
|
||||
<hr />
|
||||
</div>
|
||||
<button class="close" on:click={() => dialog.close()}>
|
||||
<CloseIcon width="0.8em" />
|
||||
</button>
|
||||
</dialog>
|
||||
|
||||
<style>
|
||||
dialog {
|
||||
max-width: 70%;
|
||||
border-radius: 0.2em;
|
||||
border: none;
|
||||
padding: 0em 2em 2em 2em;
|
||||
border-left: 2em;
|
||||
border-right: 2em;
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
box-shadow: .5em .5em .5em var(--header);
|
||||
}
|
||||
dialog::backdrop {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
dialog > div {
|
||||
padding: 1em;
|
||||
}
|
||||
dialog[open] {
|
||||
animation: zoom 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
@keyframes zoom {
|
||||
from {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
dialog[open]::backdrop {
|
||||
animation: fade 0.3s ease-out;
|
||||
}
|
||||
@keyframes fade {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 1em;
|
||||
right: 1.5em;
|
||||
color: var(--fg);
|
||||
background: transparent;
|
||||
border: 0 none;
|
||||
padding: 0;
|
||||
margin: 0 0 0 auto;
|
||||
line-height: 1;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
</style>
|
26
src/lib/components/Section.svelte
Normal file
26
src/lib/components/Section.svelte
Normal file
@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
export let label: string = "";
|
||||
</script>
|
||||
|
||||
<div id={label} class="relative flex flex-row w-full min-h-[300px] mt-5 mb-25">
|
||||
<!-- Sticky/Sliding Label -->
|
||||
<div class="hidden md:flex flex-col items-center mr-6">
|
||||
<div class="sticky top-24 left-0 z-10">
|
||||
<span class="text-2xl font-bold text-blue-400 tracking-widest"
|
||||
style="writing-mode: vertical-rl; text-orientation: mixed;">
|
||||
{label}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Main Content -->
|
||||
<div class="flex-1 flex flex-col">
|
||||
<!-- Label for mobile -->
|
||||
<div class="md:hidden mb-2">
|
||||
<span class="text-2xl font-bold text-blue-400">{label}</span>
|
||||
</div>
|
||||
<hr class="border-blue-400 mb-6" />
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
16
src/lib/components/SkillProgress.svelte
Normal file
16
src/lib/components/SkillProgress.svelte
Normal file
@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
export let value: number = 0; // 0 to 100
|
||||
</script>
|
||||
|
||||
<div class="w-full mt-3">
|
||||
<div class="flex justify-between mb-1">
|
||||
<span class="text-sm font-medium">Competency Level</span>
|
||||
<span class="text-sm font-medium">{value}%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-800 rounded-full h-5">
|
||||
<div
|
||||
class="bg-orange-400 h-5 rounded-full transition-all duration-500"
|
||||
style="width: {value}%"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
@ -1,95 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export let darkMode: boolean = true;
|
||||
|
||||
function onThemeSwitch() {
|
||||
darkMode = !darkMode;
|
||||
|
||||
localStorage.setItem('theme', darkMode ? 'dark' : 'light');
|
||||
|
||||
darkMode
|
||||
? document.documentElement.classList.add('dark')
|
||||
: document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
|
||||
if (browser) {
|
||||
if (
|
||||
localStorage.theme === 'dark' ||
|
||||
(!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
) {
|
||||
document.documentElement.classList.add('dark');
|
||||
darkMode = true;
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
darkMode = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: absolute;
|
||||
top: 0em;
|
||||
right: 0em;
|
||||
display: inline-block;
|
||||
width: 3.75em;
|
||||
height: 2.125em;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
background-color: var(--accent);
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--accent);
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 80%;
|
||||
width: 45%;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: var(--bg);
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(1.625em);
|
||||
-ms-transform: translateX(1.625em);
|
||||
transform: translateX(1.625em);
|
||||
}
|
||||
|
||||
.slider.round {
|
||||
border-radius: 2.125em;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<svelte:head>
|
||||
<link rel="stylesheet" href={`/themes/${darkMode ? 'dark' : 'light'}.css`} />
|
||||
</svelte:head>
|
||||
|
||||
|
||||
<div class="toggle-wrapper not-required">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked={darkMode} on:click={onThemeSwitch}>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
41
src/lib/components/Timeline.svelte
Normal file
41
src/lib/components/Timeline.svelte
Normal file
@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
export let timelineData: Array<{
|
||||
title: string;
|
||||
description: 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>
|
||||
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
<div class="max-w-4xl w-full">
|
||||
{#each timelineData as entry, i}
|
||||
<div class="relative border-l border-gray-700 pl-8 pb-12">
|
||||
{#if openStates[i]}
|
||||
<div class="absolute top-0 left-[8px] text-green-400 w-4 h-4">♦</div>
|
||||
{:else}
|
||||
<div class="absolute top-0 left-[8px] text-green-400 w-4 h-4">⋄</div>
|
||||
{/if}
|
||||
<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"
|
||||
on:click={() => toggle(i)}
|
||||
aria-expanded={openStates[i]}
|
||||
>
|
||||
<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>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
<script>
|
||||
export let width = "1em"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
width={width}
|
||||
style="text-align: center; display: inline-block;"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 352 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
|
||||
/>
|
||||
</svg>
|
@ -1,19 +0,0 @@
|
||||
<script>
|
||||
export let width = "1em"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
width={width}
|
||||
style="text-align: center; display: inline-block;"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M256 40c118.621 0 216 96.075 216 216 0 119.291-96.61 216-216 216-119.244 0-216-96.562-216-216 0-119.203 96.602-216 216-216m0-32C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm-11.49 120h22.979c6.823 0 12.274 5.682 11.99 12.5l-7 168c-.268 6.428-5.556 11.5-11.99 11.5h-8.979c-6.433 0-11.722-5.073-11.99-11.5l-7-168c-.283-6.818 5.167-12.5 11.99-12.5zM256 340c-15.464 0-28 12.536-28 28s12.536 28 28 28 28-12.536 28-28-12.536-28-28-28z"
|
||||
class=""
|
||||
></path>
|
||||
</svg>
|
@ -1,18 +0,0 @@
|
||||
<script>
|
||||
export let width = "1em"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
width={width}
|
||||
style="text-align: center; display: inline-block;"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M256 40c118.621 0 216 96.075 216 216 0 119.291-96.61 216-216 216-119.244 0-216-96.562-216-216 0-119.203 96.602-216 216-216m0-32C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm-36 344h12V232h-12c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h48c6.627 0 12 5.373 12 12v140h12c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12h-72c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12zm36-240c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32z"
|
||||
/>
|
||||
</svg>
|
@ -1,18 +0,0 @@
|
||||
<script>
|
||||
export let width = "1em"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
width={width}
|
||||
style="text-align: center; display: inline-block;"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 464c-118.664 0-216-96.055-216-216 0-118.663 96.055-216 216-216 118.664 0 216 96.055 216 216 0 118.663-96.055 216-216 216zm141.63-274.961L217.15 376.071c-4.705 4.667-12.303 4.637-16.97-.068l-85.878-86.572c-4.667-4.705-4.637-12.303.068-16.97l8.52-8.451c4.705-4.667 12.303-4.637 16.97.068l68.976 69.533 163.441-162.13c4.705-4.667 12.303-4.637 16.97.068l8.451 8.52c4.668 4.705 4.637 12.303-.068 16.97z"
|
||||
/>
|
||||
</svg>
|
@ -1,67 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { fade } from "svelte/transition";
|
||||
import { Toast, ToastType } from "$lib/toast";
|
||||
import SuccessIcon from "./SuccessIcon.svelte";
|
||||
import ErrorIcon from "./ErrorIcon.svelte";
|
||||
import InfoIcon from "./InfoIcon.svelte";
|
||||
import CloseIcon from "./CloseIcon.svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let toastData: Toast;
|
||||
</script>
|
||||
|
||||
<article class={toastData.type.toString().toLowerCase()} role="alert" transition:fade>
|
||||
{#if toastData.type === ToastType.Success}
|
||||
<SuccessIcon width="1.1em" />
|
||||
{:else if toastData.type === ToastType.Error}
|
||||
<ErrorIcon width="1.1em" />
|
||||
{:else}
|
||||
<InfoIcon width="1.1em" />
|
||||
{/if}
|
||||
|
||||
<div class="text">
|
||||
{toastData.text}
|
||||
</div>
|
||||
|
||||
{#if toastData.dismissable}
|
||||
<button class="close" on:click={() => dispatch("dismiss")}>
|
||||
<CloseIcon width="0.8em" />
|
||||
</button>
|
||||
{/if}
|
||||
</article>
|
||||
|
||||
<style lang="postcss">
|
||||
article {
|
||||
color: white;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 auto 0.5rem auto;
|
||||
width: 20rem;
|
||||
max-width: 80%;
|
||||
}
|
||||
.error {
|
||||
background: var(--red);
|
||||
}
|
||||
.success {
|
||||
background: var(--green);
|
||||
}
|
||||
.info {
|
||||
background: var(--blue);
|
||||
}
|
||||
.text {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.close {
|
||||
color: white;
|
||||
background: transparent;
|
||||
border: 0 none;
|
||||
padding: 0;
|
||||
margin: 0 0 0 auto;
|
||||
line-height: 1;
|
||||
font-size: 1rem;
|
||||
}
|
||||
</style>
|
@ -1,28 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Toast from "./Toast.svelte";
|
||||
|
||||
import { dismissToast, toasts } from "$lib/stores";
|
||||
</script>
|
||||
|
||||
{#if $toasts}
|
||||
<section>
|
||||
{#each $toasts as toast (toast.id)}
|
||||
<Toast toastData = {toast} on:dismiss={() => dismissToast(toast.id)} />
|
||||
{/each}
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<style lang="postcss">
|
||||
section {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
@ -1,21 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { setContext } from 'svelte';
|
||||
import type { TimelinePosition, TimelineConfig } from '../types';
|
||||
export let position: TimelinePosition = 'right';
|
||||
export let style: string = null;
|
||||
|
||||
setContext<TimelineConfig>('TimelineConfig', { rootPosition: position });
|
||||
</script>
|
||||
|
||||
<ul class="timeline" {style}>
|
||||
<slot />
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
.timeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 6px 16px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
@ -1,13 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let style: string = "";
|
||||
</script>
|
||||
|
||||
<span class="timeline-connector" {style}></span>
|
||||
|
||||
<style>
|
||||
.timeline-connector {
|
||||
width: 2px;
|
||||
background-color: #bdbdbd;
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
@ -1,30 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import type { TimelineConfig, TimelinePosition } from '../types';
|
||||
export let style: string = null;
|
||||
|
||||
const config = getContext<TimelineConfig>('TimelineConfig');
|
||||
const parentPosition = getContext<TimelinePosition>('ParentPosition');
|
||||
|
||||
const itemPosition = parentPosition ? parentPosition : config.rootPosition;
|
||||
</script>
|
||||
|
||||
<div class={`timeline-content ${itemPosition}`} {style}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.timeline-content {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin: 6px 16px;
|
||||
}
|
||||
|
||||
.left {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.right {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
@ -1,19 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let style: string = null;
|
||||
</script>
|
||||
|
||||
<span class="timeline-dot" {style}>
|
||||
<slot />
|
||||
</span>
|
||||
|
||||
<style>
|
||||
.timeline-dot {
|
||||
background-color: #121212;
|
||||
border: solid 2px #121212;
|
||||
display: flex;
|
||||
align-self: baseline;
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
margin: 11.5px 0;
|
||||
}
|
||||
</style>
|
@ -1,58 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import type { TimelinePosition, ParentPosition, TimelineConfig } from '$lib/types';
|
||||
|
||||
export let position: ParentPosition | null = null;
|
||||
export let style: string = "";
|
||||
|
||||
const config = getContext<TimelineConfig>('TimelineConfig');
|
||||
const itemPosition = position ? position : config.rootPosition;
|
||||
setContext<TimelinePosition>('ParentPosition', itemPosition);
|
||||
</script>
|
||||
|
||||
<li class={`timeline-item ${itemPosition}`} {style}>
|
||||
{#if !$$slots['opposite-content']}
|
||||
<div class="opposite-block"></div>
|
||||
{:else}
|
||||
<slot name="opposite-content" />
|
||||
{/if}
|
||||
<slot />
|
||||
</li>
|
||||
|
||||
<style>
|
||||
:global(.alternate:nth-of-type(even) > .timeline-content) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:global(.alternate:nth-of-type(odd) > .timeline-opposite-content) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.opposite-block {
|
||||
flex: 1;
|
||||
margin: 6px 16px;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
position: relative;
|
||||
min-height: 70px;
|
||||
}
|
||||
|
||||
.left {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.right {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.alternate:nth-of-type(even) {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.alternate:nth-of-type(odd) {
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
@ -1,31 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import type { TimelineConfig, TimelinePosition } from '../types';
|
||||
export let style: string = null;
|
||||
|
||||
const config = getContext<TimelineConfig>('TimelineConfig');
|
||||
const parentPosition = getContext<TimelinePosition>('ParentPosition');
|
||||
|
||||
const itemPosition = parentPosition ? parentPosition : config.rootPosition;
|
||||
</script>
|
||||
|
||||
<div class={`timeline-opposite-content ${itemPosition}`} {style}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.timeline-opposite-content {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: auto;
|
||||
margin: 6px 16px;
|
||||
}
|
||||
|
||||
.left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
@ -1,16 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let style: string = null;
|
||||
</script>
|
||||
|
||||
<div class="timeline-separator" {style}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.timeline-separator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 0;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
@ -1,41 +1,9 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
||||
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
||||
import TimelineItem from '$lib/components/timeline/TimelineItem.svelte';
|
||||
import TimelineSeparator from '$lib/components/timeline/TimelineSeparator.svelte';
|
||||
import TimelineDot from '$lib/components/timeline/TimelineDot.svelte';
|
||||
import TimelineConnector from '$lib/components/timeline/TimelineConnector.svelte';
|
||||
import TimelineContent from '$lib/components/timeline/TimelineContent.svelte';
|
||||
import TimelineOppositeContent from '$lib/components/timeline/TimelineOppositeContent.svelte';
|
||||
|
||||
import Toasts from '$lib/components/Toasts/Toasts.svelte';
|
||||
import Toast from '$lib/components/Toasts/Toast.svelte';
|
||||
import CloseIcon from '$lib/components/Toasts/CloseIcon.svelte';
|
||||
import InfoIcon from '$lib/components/Toasts/InfoIcon.svelte';
|
||||
import SuccessIcon from '$lib/components/Toasts/SuccessIcon.svelte';
|
||||
import ErrorIcon from '$lib/components/Toasts/ErrorIcon.svelte';
|
||||
|
||||
import Card from '$lib/components/Cards/Card.svelte';
|
||||
import SlidingCard from '$lib/components/Cards/SlidingCard.svelte';
|
||||
import Modal from '$lib/components/Modal.svelte';
|
||||
import FlexGallery from './components/FlexGallery.svelte';
|
||||
import Loading from './components/Loading.svelte';
|
||||
import Section from './components/Section.svelte';
|
||||
import SkillProgress from './components/SkillProgress.svelte';
|
||||
import Timeline from './components/Timeline.svelte';
|
||||
|
||||
|
||||
export {
|
||||
Timeline,
|
||||
TimelineItem,
|
||||
TimelineSeparator,
|
||||
TimelineDot,
|
||||
TimelineConnector,
|
||||
TimelineContent,
|
||||
TimelineOppositeContent,
|
||||
|
||||
Toasts,
|
||||
Toast,
|
||||
CloseIcon,
|
||||
InfoIcon,
|
||||
SuccessIcon,
|
||||
ErrorIcon,
|
||||
|
||||
Card,
|
||||
SlidingCard,
|
||||
Modal
|
||||
};
|
||||
export { Card, FlexGallery, Loading, Section, SkillProgress, Timeline };
|
||||
|
@ -1,38 +1,7 @@
|
||||
import { ToastType, type Toast } from "$lib/toast";
|
||||
import { writable, type Writable } from "svelte/store";
|
||||
import { writable } from "svelte/store";
|
||||
import type { GitRepo } from "./types";
|
||||
import { fetchRepos } from "./api/git";
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// Toast Stores
|
||||
////////////////////////////////////////
|
||||
export const toasts: Writable<Toast[]> = writable([]);
|
||||
|
||||
export const addToast = (toast: Toast) => {
|
||||
// Create a unique ID so we can easily find/remove it
|
||||
// if it is dismissible/has a timeout.
|
||||
toast.id = Math.floor(Math.random() * 10000);
|
||||
|
||||
// Setup some sensible defaults for a toast.
|
||||
const defaults = {
|
||||
id: toast.id,
|
||||
type: ToastType.Info,
|
||||
dismissible: true,
|
||||
timeout: 3000,
|
||||
};
|
||||
|
||||
// Push the toast to the top of the list of toasts
|
||||
toasts.update((all) => [{ ...defaults, ...toast }, ...all]);
|
||||
|
||||
// If toast is dismissible, dismiss it after "timeout" amount of time.
|
||||
if (toast.timeout) setTimeout(() => dismissToast(toast.id), toast.timeout);
|
||||
};
|
||||
|
||||
export const dismissToast = (id: number) => {
|
||||
toasts.update((all) => all.filter((t) => t.id !== id));
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
// Git Repo Stores
|
||||
////////////////////////////////////////
|
||||
|
@ -1,26 +0,0 @@
|
||||
/**
|
||||
* @enum Used to refer to the type of toast being displayed
|
||||
*/
|
||||
export enum ToastType {
|
||||
Info = "info",
|
||||
Success = "success",
|
||||
Error = "error"
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Toast Notification
|
||||
*/
|
||||
export class Toast {
|
||||
constructor(text: String, type: ToastType, dismissable: boolean, timeout: number ) {
|
||||
this.text = text;
|
||||
this.type = type;
|
||||
this.dismissable = dismissable;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
id: number = 0;
|
||||
text: String;
|
||||
type: ToastType;
|
||||
dismissable: Boolean;
|
||||
timeout: number;
|
||||
}
|
@ -3,7 +3,7 @@ export type TimelinePosition = 'right' | 'left' | 'alternate';
|
||||
export type ParentPosition = 'right' | 'left';
|
||||
|
||||
export type TimelineConfig = {
|
||||
rootPosition: TimelinePosition;
|
||||
rootPosition: TimelinePosition;
|
||||
};
|
||||
|
||||
export interface GitRepo {
|
||||
@ -19,4 +19,4 @@ export interface GitRepo {
|
||||
login: string;
|
||||
avatar_url: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
145
src/main.svelte
145
src/main.svelte
@ -1,107 +1,66 @@
|
||||
<script lang="ts">
|
||||
import { getJson } from "$lib/data";
|
||||
import { Toast, ToastType } from "$lib/toast";
|
||||
import { addToast } from "$lib/stores";
|
||||
import { getJson } from '$lib/data';
|
||||
import { toasts } from 'svelte-toasts';
|
||||
|
||||
import Skills from './skills.svelte';
|
||||
|
||||
import Timeline from "./timeline.svelte";
|
||||
import Loading from "$lib/components/Loading.svelte";
|
||||
import Loading from '$lib/components/Loading.svelte';
|
||||
import Section from '$lib/components/Section.svelte';
|
||||
import Card from '$lib/components/Cards/Card.svelte';
|
||||
import FlexGallery from "$lib/components/FlexGallery.svelte";
|
||||
import SkillProgress from "$lib/components/SkillProgress.svelte";
|
||||
import Timeline from '$lib/components/Timeline.svelte';
|
||||
</script>
|
||||
|
||||
{#await getJson('/json/me.json')}
|
||||
<Loading />
|
||||
{:then info}
|
||||
<div class="main-card">
|
||||
<div class="card-header">
|
||||
<h1>{info.name}</h1>
|
||||
<h3 class="not-required">{info.job_title}</h3>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="flex-container">
|
||||
<img class="profile not-required" src={info.profile_photo} alt="{info.name}'s Profile Photo">
|
||||
<p class="about">{@html info.about}</p>
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
{toasts.add({
|
||||
title: 'Welcome',
|
||||
duration: 5000,
|
||||
type: 'success',
|
||||
placement: 'bottom-center',
|
||||
showProgress: true
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h1>Skills</h1>
|
||||
<hr />
|
||||
<div class="cards">
|
||||
<Skills skills="{info.skills}"></Skills>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Main Card -->
|
||||
<Section label="[Experience]">
|
||||
<Card headerLeft={info.name} headerRight={info.job_title} footer={info.location}>
|
||||
<div class="flex flex-row items-center gap-5">
|
||||
<img
|
||||
src={info.profile_photo}
|
||||
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"
|
||||
/>
|
||||
<p>{@html info.about}</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Section>
|
||||
|
||||
<div class="container">
|
||||
<h1>Experience</h1>
|
||||
<hr />
|
||||
<!-- https://github.com/K-Sato1995/svelte-vertical-timeline -->
|
||||
<Timeline timelineData="{info.timeline}"></Timeline>
|
||||
</div>
|
||||
<!-- SKills -->
|
||||
<Section label="[Skills]">
|
||||
<FlexGallery>
|
||||
{#each info.skills as skill}
|
||||
<Card headerLeft={skill.name} footer={skill.link} containerStyle="flex-1 min-w-[250px] max-w-full md:min-w-[33%] opacity-100 hover:opacity-100 hover:scale-[105%] md:opacity-70 transition-all duration-300">
|
||||
{skill.about}
|
||||
|
||||
<div style="display: none;">{addToast(new Toast("Click on a skill to open a prompt", ToastType.Info, true, 8_000))}</div>
|
||||
<div style="display: none;">{addToast(new Toast("Welcome!", ToastType.Success, true, 7_000))}</div>
|
||||
<SkillProgress value={skill.competency} />
|
||||
</Card>
|
||||
{/each}
|
||||
</FlexGallery>
|
||||
</Section>
|
||||
|
||||
<Section label="[Experience]">
|
||||
<Timeline timelineData={info.timeline} />
|
||||
</Section>
|
||||
{:catch}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h1>Unable to load portfolio overview data</h1>
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
{toasts.add({
|
||||
title: 'Error',
|
||||
description: 'There was an error loading static site data',
|
||||
duration: 0,
|
||||
placement: 'bottom-center',
|
||||
showProgress: true
|
||||
})}
|
||||
</div>
|
||||
<div style="display: none;">{addToast(new Toast("Unable to load me.json", ToastType.Error, true, 3000))}</div>
|
||||
{/await}
|
||||
|
||||
<style>
|
||||
.main-card {
|
||||
background-color: var(--bg-secondary);
|
||||
border-radius: 1em;
|
||||
padding: .2em 2em 2em 2em;
|
||||
box-shadow: .5em .5em .5em var(--glow);
|
||||
margin-bottom: 4em;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.profile {
|
||||
border-radius: 100%;
|
||||
height: 8em;
|
||||
width: 8em;
|
||||
padding: 1em 1em 1em 1em;
|
||||
border: .25em solid var(--accent);
|
||||
}
|
||||
|
||||
.about {
|
||||
padding: 0em 5% 0em 5%;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.flex-container {
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.about {
|
||||
font-size: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
.card-header h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.card-header h3 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,60 +1,23 @@
|
||||
<script lang="ts">
|
||||
import Toasts from "$lib/components/Toasts/Toasts.svelte";
|
||||
import ThemeSwitcher from "$lib/components/ThemeSwitcher.svelte";
|
||||
import { ToastContainer, FlatToast } from 'svelte-toasts';
|
||||
import '../app.css';
|
||||
</script>
|
||||
|
||||
<nav>
|
||||
<a href = "/">//Profile</a>
|
||||
<a href = "/repos">//Repos</a>
|
||||
<a href = "/contact">//Contact</a>
|
||||
<ThemeSwitcher />
|
||||
</nav>
|
||||
<div
|
||||
class="min-h-screen px-8 py-4 bg-white text-slate-600 dark:bg-slate-900/90 dark:text-slate-200/60 md:text-2xl sm:text-md font-mono flex flex-col gap-5 transition duration-1000 ease-in-out"
|
||||
>
|
||||
<nav
|
||||
class="w-full px-8 py-4 flex gap-10 text-xl justify-center items-center text-green-600 font-semibold"
|
||||
>
|
||||
<a href="/" class="hover:underline">//Profile</a>
|
||||
<a href="/repos" class="hover:underline">//Repos</a>
|
||||
<a href="/contact" class="hover:underline">//Contact</a>
|
||||
</nav>
|
||||
|
||||
<div class="main-container fade">
|
||||
<Toasts />
|
||||
<slot />
|
||||
<div class="container mx-auto justify-center items-center flex flex-col">
|
||||
<slot />
|
||||
<ToastContainer let:data>
|
||||
<FlatToast {data} />
|
||||
</ToastContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.main-container {
|
||||
margin-left: 10%;
|
||||
margin-right: 10%;
|
||||
padding-top: 2em;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.main-container {
|
||||
margin: 0em;
|
||||
padding-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
font-size: 110%;
|
||||
overflow: visible;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1.5em;
|
||||
padding: 0em 0em 1.5em 0em;
|
||||
z-index: 2;
|
||||
height: 1.5em;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.fade {
|
||||
-webkit-animation: fadeinout 1s linear forwards;
|
||||
animation: fadeinout 1s linear forwards;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeinout {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes fadeinout {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
</style>
|
@ -2,4 +2,6 @@
|
||||
import Main from '../main.svelte';
|
||||
</script>
|
||||
|
||||
<Main></Main>
|
||||
<div>
|
||||
<Main></Main>
|
||||
</div>
|
@ -1,149 +1,95 @@
|
||||
<script lang="ts">
|
||||
import { toasts } from 'svelte-toasts';
|
||||
import Card from '$lib/components/Cards/Card.svelte';
|
||||
import { Toast, ToastType } from '$lib/toast';
|
||||
import { addToast } from '$lib/stores';
|
||||
|
||||
import { page } from '$app/stores';
|
||||
const sent = $page.url.searchParams.get('sent');
|
||||
import { page } from '$app/state';
|
||||
const sent = page.url.searchParams.get('sent');
|
||||
|
||||
if (sent == 'true') {
|
||||
addToast(
|
||||
new Toast(
|
||||
'Thank you! Your E-Mail has been sent. I will reply as soon as possible!',
|
||||
ToastType.Success,
|
||||
true,
|
||||
5000
|
||||
)
|
||||
);
|
||||
toasts.add({
|
||||
title: 'Message sent!',
|
||||
description: 'Thank you for contacting me.',
|
||||
type: 'success',
|
||||
duration: 4000,
|
||||
placement: 'bottom-center'
|
||||
});
|
||||
}
|
||||
// Can't use else otherwise the warning will display on load
|
||||
|
||||
if (sent == 'false') {
|
||||
addToast(
|
||||
new Toast(
|
||||
'Sorry, your E-Mail could not be sent... Please try again later!',
|
||||
ToastType.Error,
|
||||
true,
|
||||
5000
|
||||
)
|
||||
);
|
||||
toasts.add({
|
||||
title: 'Message not sent!',
|
||||
description: 'Please try again later.',
|
||||
type: 'error',
|
||||
duration: 4000,
|
||||
placement: 'bottom-center'
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card>
|
||||
<div slot="header">
|
||||
<h2>Contact</h2>
|
||||
</div>
|
||||
<div slot="content">
|
||||
<form action="https://api.staticforms.xyz/submit" method="post" class="contact-form">
|
||||
<Card headerLeft="Contact Me">
|
||||
<!-- Contact Form -->
|
||||
<form class="w-full max-w-3xl mx-auto flex flex-col gap-4 text-lg" action="https://api.staticforms.xyz/submit" method="post">
|
||||
<div class="hidden">
|
||||
<input type="hidden" name="accessKey" value="fbb5ec04-506b-448a-a445-a2e47579a966">
|
||||
|
||||
<!-- Form Items-->
|
||||
<div class="input-group">
|
||||
<input type="text" id="name" name="name" required placeholder="Your Name" />
|
||||
<input type="email" id="email" name="email" required placeholder="Your Email" />
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" name="subject" placeholder="Subject" required>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<textarea id="message" name="message" rows="4" required placeholder="Your Message"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Hidden Attributes-->
|
||||
<input type="hidden" name="replyTo" value="@">
|
||||
<input type="text" name="honeypot" style="display: none;">
|
||||
<input type="hidden" name="redirectTo" value="https://luke-else.co.uk/contact?sent=true">
|
||||
|
||||
<!-- reCAPTCHA integration -->
|
||||
<div class="input-group">
|
||||
<div class="g-recaptcha" data-sitekey="6LfjQAwrAAAAAIF57u8Wt4w5L5vBEWi5DfXXBuGy"></div>
|
||||
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||
</div>
|
||||
<div class="flex flex-col md:flex-row gap-3">
|
||||
<div class="flex-1">
|
||||
<label class="block text-xs font-medium mb-1" for="name">Name</label>
|
||||
<input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
class="w-full rounded-lg border border-gray-400 px-3 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-600 transition placeholder-gray-400"
|
||||
required
|
||||
placeholder="Your name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<button type="submit" class="submit-button">Send Message</button>
|
||||
<div class="flex-1">
|
||||
<label class="block text-xs font-medium mb-1" for="email">Email</label>
|
||||
<input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
class="w-full rounded-lg border border-gray-400 px-3 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-600 transition placeholder-gray-400"
|
||||
required
|
||||
placeholder="you@email.com"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<a href="/Luke Else - CV.pdf" target="_blank" rel="noopener noreferrer">Curriculum Vitae</a>
|
||||
<a href="mailto:contact@luke-else.co.uk">E-Mail</a>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<label class="block text-xs font-medium mb-1" for="subject">Subject</label>
|
||||
<input
|
||||
id="subject"
|
||||
name="subject"
|
||||
type="text"
|
||||
class="w-full rounded-lg border border-gray-400 px-3 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-600 transition placeholder-gray-400"
|
||||
required
|
||||
placeholder="Subject"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium mb-1" for="message">Message</label>
|
||||
<textarea
|
||||
id="message"
|
||||
name="message"
|
||||
class="w-full rounded-lg border border-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-600 transition min-h-[80px] placeholder-gray-400"
|
||||
required
|
||||
placeholder="Your message"
|
||||
></textarea>
|
||||
</div>
|
||||
<!-- reCAPTCHA integration -->
|
||||
<div class="">
|
||||
<div class="g-recaptcha" data-sitekey="6LfjQAwrAAAAAIF57u8Wt4w5L5vBEWi5DfXXBuGy"></div>
|
||||
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="self-end bg-blue-600 hover:bg-blue-700 text-white font-semibold py-1.5 px-8 rounded-lg transition"
|
||||
>
|
||||
Send Message
|
||||
</button>
|
||||
</form>
|
||||
</Card>
|
||||
|
||||
<style>
|
||||
|
||||
/* Contact form styling */
|
||||
.contact-form {
|
||||
background: none;
|
||||
padding: 1rem;
|
||||
width: 80%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* Input groups */
|
||||
.input-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Input fields and textarea */
|
||||
.contact-form input,
|
||||
.contact-form textarea {
|
||||
padding: 0.8rem 1rem;
|
||||
border: 1px solid var(--fg);
|
||||
border-radius: 0.5rem;
|
||||
background: var(--input);
|
||||
color: var(--fg);
|
||||
font-size: 1rem;
|
||||
transition: border-color 0.3s ease, background 0.3s ease;
|
||||
}
|
||||
|
||||
.contact-form button {
|
||||
border: 1px solid var(--fg);
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.contact-form textarea {
|
||||
width: 100%;
|
||||
min-width: none;
|
||||
resize: vertical;
|
||||
min-height: fit-content;
|
||||
}
|
||||
|
||||
.contact-form input:focus,
|
||||
.contact-form textarea:focus {
|
||||
border-color: var(--glow);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Submit button */
|
||||
.submit-button {
|
||||
padding: 0.8rem 1rem;
|
||||
background: var(--accent);
|
||||
color: var(--fg);
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.submit-button:hover {
|
||||
background: var(--link);
|
||||
color: var(--input);
|
||||
}
|
||||
|
||||
.g-recaptcha {
|
||||
width: fit-content;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,64 +1,46 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { Toast, ToastType } from "$lib/toast";
|
||||
import { repos, loadRepos, addToast } from "$lib/stores";
|
||||
import { timeSince, checkImage, IMAGE_URL_SUFFIX } from "$lib/api/git";
|
||||
import Card from "$lib/components/Cards/Card.svelte";
|
||||
import SlidingCard from "$lib/components/Cards/SlidingCard.svelte";
|
||||
import Loading from "$lib/components/Loading.svelte";
|
||||
import { loadRepos, repos } from '$lib/stores'; import { onMount } from 'svelte';
|
||||
import { timeSince, checkImage, IMAGE_URL_SUFFIX } from '$lib/api/git';
|
||||
|
||||
import FlexGallery from '$lib/components/FlexGallery.svelte';
|
||||
import Card from '$lib/components/Cards/Card.svelte';
|
||||
|
||||
let repoImages: Record<string, string | null> = {};
|
||||
|
||||
// When repos load, check for images
|
||||
$: if ($repos.length) {
|
||||
(async () => {
|
||||
for (const repo of $repos) {
|
||||
if (repoImages[repo.name] === undefined) {
|
||||
const url = repo.html_url + IMAGE_URL_SUFFIX;
|
||||
repoImages[repo.name] = (await checkImage(repo)) ? url : null;
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
onMount(loadRepos);
|
||||
</script>
|
||||
|
||||
<h1>My Projects</h1>
|
||||
<p>This here is a list of my most recently worked on projects. Note this does not show any private repositories. For more in depth information <a href="https://git.luke-else.co.uk">Click Here</a>.</p>
|
||||
|
||||
<div class="container">
|
||||
{#if $repos.length > 0}
|
||||
<div style="display: none;">{addToast(new Toast("See a snapshot of my latest work.", ToastType.Info, true, 8_000))}</div>
|
||||
<div class="cards">
|
||||
{#each $repos as repo}
|
||||
{#await checkImage(repo)}
|
||||
<Loading />
|
||||
{:then hasImage}
|
||||
{#if hasImage}
|
||||
<SlidingCard>
|
||||
<div slot="header">
|
||||
<h2>{repo.name}</h2>
|
||||
{repo.language}
|
||||
</div>
|
||||
<div slot="content">
|
||||
<p class="not-required">{@html repo.description}</p>
|
||||
</div>
|
||||
<div slot="sliding-content">
|
||||
<img width="100%" src="{repo.html_url}{IMAGE_URL_SUFFIX}" alt="{repo.name}" />
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<!-- svelte-ignore a11y-invalid-attribute -->
|
||||
<a href="{repo.html_url}">{repo.name}</a>
|
||||
{timeSince(repo.updated_at)}
|
||||
</div>
|
||||
</SlidingCard>
|
||||
{:else}
|
||||
<Card>
|
||||
<div slot="header">
|
||||
<h2>{repo.name}</h2>
|
||||
{repo.language}
|
||||
</div>
|
||||
<div slot="content">
|
||||
<p class="not-required">{@html repo.description}</p>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<!-- svelte-ignore a11y-invalid-attribute -->
|
||||
<a href="{repo.html_url}">{repo.name}</a>
|
||||
{timeSince(repo.updated_at)}
|
||||
</div>
|
||||
</Card>
|
||||
{/if}
|
||||
{/await}
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<Loading />
|
||||
{/if}
|
||||
</div>
|
||||
<FlexGallery>
|
||||
{#each $repos as repo}
|
||||
<Card
|
||||
headerLeft={repo.name}
|
||||
headerRight={repo.language}
|
||||
footer={timeSince(repo.updated_at)}
|
||||
containerStyle="group relative flex-1 min-w-[250px] max-w-full md:min-w-[33%] opacity-100 hover:opacity-100 hover:scale-[105%] md:opacity-70 transition-all duration-300 overflow-hidden"
|
||||
>
|
||||
<div class="relative z-0">
|
||||
{repo.description}
|
||||
</div>
|
||||
{#if repoImages[repo.name]}
|
||||
<!-- svelte-ignore a11y_img_redundant_alt -->
|
||||
<img
|
||||
src={repoImages[repo.name]}
|
||||
alt="repo image"
|
||||
class="absolute left-0 bottom-0 h-full w-full object-cover rounded-2xl transition-transform duration-500 translate-y-full group-hover:translate-y-0 z-10 pointer-events-none"
|
||||
/>
|
||||
{/if}
|
||||
</Card>
|
||||
{/each}
|
||||
</FlexGallery>
|
||||
|
@ -1,59 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let skills: any;
|
||||
|
||||
import Card from '$lib/components/Cards/Card.svelte';
|
||||
import Modal from '$lib/components/Modal.svelte';
|
||||
|
||||
let showModal: boolean = false;
|
||||
let activeModal: any = null;
|
||||
</script>
|
||||
|
||||
{#each skills as skill}
|
||||
<Card on:click={() => {showModal = true; activeModal = skill}}>
|
||||
<div slot="header">
|
||||
<h2>{skill.skill}</h2>
|
||||
<i class="{skill.logo} logo"></i>
|
||||
</div>
|
||||
<div slot="content">
|
||||
<p class="not-required">{@html skill.usage}</p>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<!-- svelte-ignore a11y-invalid-attribute -->
|
||||
<a href="#">View More</a>
|
||||
<a href="/repos">Repos</a>
|
||||
</div>
|
||||
</Card>
|
||||
{/each}
|
||||
|
||||
<!--Modal to be displayed on click-->
|
||||
{#if activeModal != null}
|
||||
<Modal bind:showModal>
|
||||
<h2 slot="header" class="card-header">
|
||||
{activeModal.skill}
|
||||
<i class="{activeModal.logo} logo"></i>
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
{activeModal.about}
|
||||
</p>
|
||||
|
||||
<div class="card-footer">
|
||||
<a href="{activeModal.link}" target="_blank" rel="noopener noreferrer">Learn More</a>
|
||||
<a href="/repos">Repos</a>
|
||||
</div>
|
||||
</Modal>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.card-footer {
|
||||
margin-bottom: 1em;
|
||||
display: flex;
|
||||
gap: 1.5em;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.logo {
|
||||
color: var(--fg);
|
||||
font-size: 3em;
|
||||
}
|
||||
</style>
|
@ -1,63 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let timelineData: any;
|
||||
|
||||
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
||||
import TimelineItem from '$lib/components/timeline/TimelineItem.svelte';
|
||||
import TimelineSeparator from '$lib/components/timeline/TimelineSeparator.svelte';
|
||||
import TimelineDot from '$lib/components/timeline/TimelineDot.svelte';
|
||||
import TimelineConnector from '$lib/components/timeline/TimelineConnector.svelte';
|
||||
import TimelineContent from '$lib/components/timeline/TimelineContent.svelte';
|
||||
import TimelineOppositeContent from '$lib/components/timeline/TimelineOppositeContent.svelte';
|
||||
</script>
|
||||
|
||||
<Timeline
|
||||
position="alternate"
|
||||
style={`
|
||||
border-radius: 3%;
|
||||
padding: 1rem;
|
||||
`}
|
||||
>
|
||||
{#each timelineData as item}
|
||||
<TimelineItem>
|
||||
<TimelineOppositeContent slot="opposite-content">
|
||||
<p class="oposite-content-title">{item.duration}</p>
|
||||
</TimelineOppositeContent>
|
||||
|
||||
<TimelineSeparator>
|
||||
{#if item.duration.includes('Present') || !item.duration.includes('-')}
|
||||
<div class="elementToFadeInAndOut">
|
||||
<TimelineDot style={`background-color: var(--link); border-color: var(--accent);`} />
|
||||
</div>
|
||||
{:else}
|
||||
<TimelineDot style={`background-color: var(--link); border-color: var(--accent);`} />
|
||||
{/if}
|
||||
<TimelineConnector />
|
||||
</TimelineSeparator>
|
||||
<TimelineContent>
|
||||
<h3 class="content-title">{item.title}</h3>
|
||||
<p class="content-description">{@html item.description}</p>
|
||||
</TimelineContent>
|
||||
</TimelineItem>
|
||||
{/each}
|
||||
</Timeline>
|
||||
|
||||
<style>
|
||||
.oposite-content-title {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--accent);
|
||||
}
|
||||
.content-title {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.content-description {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-top: 1rem;
|
||||
color: var(--fg);
|
||||
font-weight: lighter;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
</style>
|
@ -1,42 +1,48 @@
|
||||
{
|
||||
"name": "Luke Else",
|
||||
"job_title": "Software Engineer",
|
||||
"location": "Crawley, Sussex <br /> UK",
|
||||
"profile_photo": "/profile.jpg",
|
||||
"skills": [
|
||||
{
|
||||
"skill": "Rust",
|
||||
"name": "Rust",
|
||||
"logo": "devicon-rust-plain",
|
||||
"link": "https://rust-lang.org",
|
||||
"usage": "Rust is a memory-safe language with zero-cost abstractions, making it ideal for embedded systems. I used Rust to build a <a href='https://git.luke-else.co.uk/luke-else/esp32_gps_display'>GPS-based speedometer</a> for my car and a <a href='https://git.luke-else.co.uk/luke-else/subnet_calculator'>Subnet Calculator</a> for university studies.",
|
||||
"about": "Rust combines safety, efficiency, and clean code, making it a powerful choice for reliable software development."
|
||||
"about": "Rust combines safety, efficiency, and clean code, making it a powerful choice for reliable software development.",
|
||||
"competency": 70
|
||||
},
|
||||
{
|
||||
"skill": "C++",
|
||||
"name": "C++",
|
||||
"logo": "devicon-cplusplus-plain",
|
||||
"link": "https://cplusplus.com/",
|
||||
"usage": "Since joining Thales in 2022, I’ve worked on a distributed simulation system using C++, primarily with <a href='https://www.qt.io'>Qt</a> and <a href='https://github.com/ocornut/imgui'>ImGui</a> to develop customer-facing applications.",
|
||||
"about": "C++ offers high-level abstractions with low-level control, making it essential for performance-critical applications."
|
||||
"about": "C++ offers high-level abstractions with low-level control, making it essential for performance-critical applications.",
|
||||
"competency": 80
|
||||
},
|
||||
{
|
||||
"skill": "Git",
|
||||
"name": "Git",
|
||||
"logo": "devicon-git-plain",
|
||||
"link": "https://git-scm.com",
|
||||
"usage": "I have extensive experience with Git, including advanced features like <a href='https://www.atlassian.com/git/tutorials/advanced-overview'>branching, merging and hooks</a>. I've also set up self-hosted <a href='https://git.luke-else.co.uk/luke-else/'>Git services</a> with CI/CD automation.",
|
||||
"about": "Git is an essential tool for version control, enabling efficient collaboration and streamlined code management."
|
||||
"about": "Git is an essential tool for version control, enabling efficient collaboration and streamlined code management.",
|
||||
"competency": 80
|
||||
},
|
||||
{
|
||||
"skill": "Docker",
|
||||
"name": "Docker",
|
||||
"logo": "devicon-docker-plain",
|
||||
"link": "https://docker.com",
|
||||
"usage": "I use Docker and Docker Compose for containerized deployments, including hosting <a href='https://git.luke-else.co.uk/luke-else/server'>home-lab services</a> such as this <a href='https://git.luke-else.co.uk/luke-else/luke-else.co.uk'>website</a> and remote Git repositories.",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"skill": "Svelte",
|
||||
"name": "Svelte",
|
||||
"logo": "devicon-svelte-plain",
|
||||
"link": "https://svelte.dev",
|
||||
"usage": "I built <a href='https://git.luke-else.co.uk/luke-else/luke-else.co.uk'>this website</a> using Svelte and plan to explore <a href='https://github.com/tauri-apps/tauri'>Tauri</a> for building desktop apps.",
|
||||
"about": "Svelte compiles to optimized JavaScript, offering a fast, efficient, and maintainable front-end development experience."
|
||||
"about": "Svelte compiles to optimized JavaScript, offering a fast, efficient, and maintainable front-end development experience.",
|
||||
"competency": 40
|
||||
}
|
||||
],
|
||||
"about": "Hello! I'm an enthusiastic, dedicated software engineer passionate about backend development, networking, and embedded systems. I am currently employed at <a href='https://www.thalesgroup.com/en'>Thales UK</a> and thrive on architecting robust backend solutions, optimizing data transmission, and crafting efficient embedded software. I love tackling complex challenges, collaborating with fellow professionals, and staying up-to-date with tech trends such as my current venture in learning <a href='https://rust-lang.org'>Rust-Lang</a>.",
|
||||
|
@ -1,18 +0,0 @@
|
||||
:root {
|
||||
--bg: #f2f6f7; /* Soft blue-tinted white */
|
||||
--bg-secondary: #d7e1e4; /* Cool grey-blue */
|
||||
--accent: #92a9b0; /* Subtle blue-green */
|
||||
|
||||
--header: #5d7075; /* Deep slate blue-green */
|
||||
--fg: #3c4649; /* Rich dark grey */
|
||||
|
||||
--input: #e0e6e8; /* Light desaturated blue-grey */
|
||||
|
||||
--link: #678d97; /* Muted sea blue */
|
||||
--glow: #b2c4c8; /* Gentle cool glow */
|
||||
--hover: #8fa7af; /* Soft grey-blue hover */
|
||||
|
||||
--green: #78a890; /* Balanced green */
|
||||
--red: #e08c96; /* Soft dusty red */
|
||||
--blue: #729da5; /* Medium desaturated blue */
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
:root {
|
||||
--bg: #282c34;
|
||||
--bg-secondary: #3e434b;
|
||||
--accent: #59616d;
|
||||
|
||||
--header: #E06C75;
|
||||
--fg: #9eaac0;
|
||||
|
||||
--input: #2b3136;
|
||||
|
||||
--link: #98C379;
|
||||
--glow: #C678DD;
|
||||
--hover: #56B6C2;
|
||||
|
||||
--green: #98C379;
|
||||
--red: #E06C75;
|
||||
--blue: #79aec3;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
:root {
|
||||
--bg: #1e1f2a;
|
||||
--bg-secondary: #3a3f4b;
|
||||
--accent: #777f8d;
|
||||
|
||||
--header: #cad1da;
|
||||
--fg: #e4e1db;
|
||||
|
||||
--input: #2e3438;
|
||||
|
||||
--link: #95add8;
|
||||
--glow: #bcc3ca;
|
||||
--hover: #cdd8e2;
|
||||
|
||||
--green: #98C379;
|
||||
--red: #E06C75;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
:root {
|
||||
--bg: #2b2b2b; /* Dark but not too harsh */
|
||||
--bg-secondary: #3c3f41; /* Deep warm grey */
|
||||
--accent: #6897bb; /* Muted but clear blue */
|
||||
|
||||
--header: #a9b7c6; /* Softer contrast */
|
||||
--fg: #bbbbbb; /* Light but not pure white */
|
||||
|
||||
--input: #414141; /* Dark grey input */
|
||||
|
||||
--link: #519aba; /* Soft coding blue */
|
||||
--glow: #4e5d68; /* Subtle bluish glow */
|
||||
--hover: #8c9da8; /* Brighter on hover */
|
||||
|
||||
--green: #6a8759; /* Classic Darcula green */
|
||||
--red: #cc6666; /* Softer, warm red */
|
||||
--blue: #6897bb; /* Standard coding blue */
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
:root {
|
||||
--bg: #f5f5f5; /* Slightly deeper light grey for subtle contrast */
|
||||
--bg-secondary: #d9dddf; /* More defined soft grey */
|
||||
--accent: #8ea29b; /* Stronger muted sage green */
|
||||
|
||||
--header: #4a5a56; /* Darker desaturated green-grey for better contrast */
|
||||
--fg: #2f3739; /* Richer dark grey for improved readability */
|
||||
|
||||
--input: #e4e7e8; /* Slightly deeper soft grey input background */
|
||||
|
||||
--link: #5f8480; /* Darker muted teal for contrast */
|
||||
--glow: #b0bdb9; /* More noticeable but soft glow */
|
||||
--hover: #85a29c; /* Stronger pastel hover effect */
|
||||
|
||||
--green: #6fa984; /* More vibrant pastel green */
|
||||
--red: #e8858f; /* Slightly deeper pastel red for contrast */
|
||||
--blue: #6fa9a4; /* Same as accent */
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
:root {
|
||||
--bg: #272822; /* Classic Monokai dark */
|
||||
--bg-secondary: #3e3d32; /* Darker olive grey */
|
||||
--accent: #f92672; /* Monokai’s signature pink-red */
|
||||
|
||||
--header: #a6e22e; /* Neon green */
|
||||
--fg: #f8f8f2; /* Soft off-white */
|
||||
|
||||
--input: #373831; /* Slightly lighter grey-green */
|
||||
|
||||
--link: #66d9ef; /* Monokai cyan */
|
||||
--glow: #49483e; /* Muted background glow */
|
||||
--hover: #fd7c95; /* Lighter pink hover */
|
||||
|
||||
--green: #a6e22e; /* Bright Monokai green */
|
||||
--red: #f92672; /* Soft pinkish-red */
|
||||
--blue: #66d9ef; /* Bright cyan */
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
:root {
|
||||
--bg: #1e1e1e; /* Dark neutral background */
|
||||
--bg-secondary: #252526; /* Slightly lighter for separation */
|
||||
--accent: #569cd6; /* Signature VS Code blue */
|
||||
|
||||
--header: #9cdcfe; /* Brighter cyan for contrast */
|
||||
--fg: #d4d4d4; /* Light grey for readability */
|
||||
|
||||
--input: #333; /* Dark but still visible */
|
||||
|
||||
--link: #4fc1ff; /* Brighter blue for hyperlinks */
|
||||
--glow: #2a3f5f; /* Soft deep blue glow */
|
||||
--hover: #7bb8e8; /* Brighter accent on hover */
|
||||
|
||||
--green: #4ec9b0; /* Soft green */
|
||||
--red: #d16969; /* Coding red */
|
||||
--blue: #9cdcfe; /* Soft bright cyan */
|
||||
}
|
19
tailwind.config.js
Normal file
19
tailwind.config.js
Normal file
@ -0,0 +1,19 @@
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
'one-bg': '#282c34',
|
||||
'one-bg-light': '#3a3f4b',
|
||||
'one-fg': '#abb2bf',
|
||||
'one-accent': '#61afef',
|
||||
'one-green': '#98c379',
|
||||
'one-orange': '#d19a66',
|
||||
'one-red': '#e06c75',
|
||||
'one-yellow': '#e5c07b',
|
||||
'one-purple': '#c678dd',
|
||||
'one-cyan': '#56b6c2',
|
||||
'one-comment': '#5c6370',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
plugins: [
|
||||
tailwindcss(),
|
||||
sveltekit(),
|
||||
]
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user