Compare commits

..

1 Commits

Author SHA1 Message Date
c9be2af52e WIP 2024-05-25 12:24:45 +03:00
88 changed files with 6184 additions and 1179 deletions

View File

@@ -1,6 +1,3 @@
{
"extends": "next/core-web-vitals",
"rules": {
"@next/next/no-img-element": "off"
}
"extends": "next/core-web-vitals"
}

3
.gitignore vendored
View File

@@ -33,6 +33,3 @@ yarn-error.log*
# typescript
*.tsbuildinfo
# build folder
/dist

343
bun.lock
View File

@@ -1,343 +0,0 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "runosaari",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.4.0",
"react-router-dom": "^6.22.0",
"react-transition-group": "^4.4.2",
"reactstrap": "^9.1.1",
"sass": "^1.101.0",
},
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/react-transition-group": "^4.4.4",
"@vitejs/plugin-react": "^4.2.0",
"typescript": "^5.3.0",
"vite": "^5.1.0",
},
},
},
"packages": {
"@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
"@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="],
"@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="],
"@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="],
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
"@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="],
"@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="],
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
"@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="],
"@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
"@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="],
"@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@parcel/watcher": ["@parcel/watcher@2.5.6", "", { "dependencies": { "detect-libc": "^2.0.3", "is-glob": "^4.0.3", "node-addon-api": "^7.0.0", "picomatch": "^4.0.3" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.6", "@parcel/watcher-darwin-arm64": "2.5.6", "@parcel/watcher-darwin-x64": "2.5.6", "@parcel/watcher-freebsd-x64": "2.5.6", "@parcel/watcher-linux-arm-glibc": "2.5.6", "@parcel/watcher-linux-arm-musl": "2.5.6", "@parcel/watcher-linux-arm64-glibc": "2.5.6", "@parcel/watcher-linux-arm64-musl": "2.5.6", "@parcel/watcher-linux-x64-glibc": "2.5.6", "@parcel/watcher-linux-x64-musl": "2.5.6", "@parcel/watcher-win32-arm64": "2.5.6", "@parcel/watcher-win32-ia32": "2.5.6", "@parcel/watcher-win32-x64": "2.5.6" } }, "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ=="],
"@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.6", "", { "os": "android", "cpu": "arm64" }, "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A=="],
"@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA=="],
"@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg=="],
"@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng=="],
"@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ=="],
"@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg=="],
"@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA=="],
"@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA=="],
"@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ=="],
"@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg=="],
"@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q=="],
"@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g=="],
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="],
"@popperjs/core": ["@popperjs/core@2.11.5", "", {}, "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw=="],
"@remix-run/router": ["@remix-run/router@1.23.2", "", {}, "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.2", "", { "os": "android", "cpu": "arm" }, "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.2", "", { "os": "android", "cpu": "arm64" }, "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.2", "", { "os": "linux", "cpu": "arm" }, "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.2", "", { "os": "linux", "cpu": "arm" }, "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A=="],
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw=="],
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.2", "", { "os": "linux", "cpu": "x64" }, "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.2", "", { "os": "linux", "cpu": "x64" }, "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw=="],
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.2", "", { "os": "none", "cpu": "arm64" }, "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.2", "", { "os": "win32", "cpu": "x64" }, "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.2", "", { "os": "win32", "cpu": "x64" }, "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA=="],
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
"@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/prop-types": ["@types/prop-types@15.7.5", "", {}, "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="],
"@types/react": ["@types/react@18.3.28", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw=="],
"@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="],
"@types/react-transition-group": ["@types/react-transition-group@4.4.4", "", { "dependencies": { "@types/react": "*" } }, "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug=="],
"@types/scheduler": ["@types/scheduler@0.16.2", "", {}, "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="],
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.24", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-I2NkZOOrj2XuguvWCK6OVh9GavsNjZjK908Rq3mIBK25+GD8vPX5w2WdxVqnQ7xx3SrZJiCiZFu+/Oz50oSYSA=="],
"browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="],
"caniuse-lite": ["caniuse-lite@1.0.30001787", "", {}, "sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg=="],
"chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"classnames": ["classnames@2.3.1", "", {}, "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="],
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="],
"electron-to-chromium": ["electron-to-chromium@1.5.344", "", {}, "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg=="],
"esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
"immutable": ["immutable@5.1.5", "", {}, "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": "cli.js" }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": "bin/nanoid.cjs" }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
"node-releases": ["node-releases@2.0.38", "", {}, "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
"postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="],
"prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
"react-fast-compare": ["react-fast-compare@3.2.0", "", {}, "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="],
"react-icons": ["react-icons@4.4.0", "", { "peerDependencies": { "react": "*" } }, "sha512-fSbvHeVYo/B5/L4VhB7sBA1i2tS8MkT0Hb9t2H1AVPkwGfVHLJCqyr2Py9dKMxsyM63Eng1GkdZfbWj+Fmv8Rg=="],
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
"react-popper": ["react-popper@2.3.0", "", { "dependencies": { "react-fast-compare": "^3.0.1", "warning": "^4.0.2" }, "peerDependencies": { "@popperjs/core": "^2.0.0", "react": "^16.8.0 || ^17 || ^18", "react-dom": "^16.8.0 || ^17 || ^18" } }, "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q=="],
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
"react-router": ["react-router@6.30.3", "", { "dependencies": { "@remix-run/router": "1.23.2" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw=="],
"react-router-dom": ["react-router-dom@6.30.3", "", { "dependencies": { "@remix-run/router": "1.23.2", "react-router": "6.30.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag=="],
"react-transition-group": ["react-transition-group@4.4.2", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg=="],
"reactstrap": ["reactstrap@9.1.1", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@popperjs/core": "^2.6.0", "classnames": "^2.2.3", "prop-types": "^15.5.8", "react-popper": "^2.2.4", "react-transition-group": "^4.4.2" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-XlQI5qKHQ4QMpye4GxLgoj8rv+qsypvzMcs2KA11DeYjT82LcS48ttfNqOodDYyeCYv8t89gd9THXkjGhoYp5A=="],
"readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"rollup": ["rollup@4.60.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.2", "@rollup/rollup-android-arm64": "4.60.2", "@rollup/rollup-darwin-arm64": "4.60.2", "@rollup/rollup-darwin-x64": "4.60.2", "@rollup/rollup-freebsd-arm64": "4.60.2", "@rollup/rollup-freebsd-x64": "4.60.2", "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", "@rollup/rollup-linux-arm-musleabihf": "4.60.2", "@rollup/rollup-linux-arm64-gnu": "4.60.2", "@rollup/rollup-linux-arm64-musl": "4.60.2", "@rollup/rollup-linux-loong64-gnu": "4.60.2", "@rollup/rollup-linux-loong64-musl": "4.60.2", "@rollup/rollup-linux-ppc64-gnu": "4.60.2", "@rollup/rollup-linux-ppc64-musl": "4.60.2", "@rollup/rollup-linux-riscv64-gnu": "4.60.2", "@rollup/rollup-linux-riscv64-musl": "4.60.2", "@rollup/rollup-linux-s390x-gnu": "4.60.2", "@rollup/rollup-linux-x64-gnu": "4.60.2", "@rollup/rollup-linux-x64-musl": "4.60.2", "@rollup/rollup-openbsd-x64": "4.60.2", "@rollup/rollup-openharmony-arm64": "4.60.2", "@rollup/rollup-win32-arm64-msvc": "4.60.2", "@rollup/rollup-win32-ia32-msvc": "4.60.2", "@rollup/rollup-win32-x64-gnu": "4.60.2", "@rollup/rollup-win32-x64-msvc": "4.60.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ=="],
"sass": ["sass@1.101.0", "", { "dependencies": { "chokidar": "^5.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw=="],
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
"semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
"vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="],
"warning": ["warning@4.0.3", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w=="],
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"@types/react-transition-group/@types/react": ["@types/react@18.0.11", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-JxSwm54IgMW4XTR+zFF5QpNx4JITmFbB4WHR2J0vg9RpjNeyqEMlODXsD2e64br6GX70TL0UYjZJETpyyC1WdA=="],
"dom-helpers/csstype": ["csstype@3.1.0", "", {}, "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="],
"@types/react-transition-group/@types/react/csstype": ["csstype@3.1.0", "", {}, "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="],
}
}

View File

@@ -7,8 +7,6 @@ const Performers: Array<Performer> = [
{ name: 'Katariina Vuorinen', paragraphs: ['Katariina Vuorinen on runoilija, löytöretkeilijä ja Runosaari-festivaalin luoja. Vuonna 2018 hän löysi nomadivuosiensa keskeltä maagisen Velkuanmaan saaren, ja tiesi heti paikan kutsuvan runon henkiä saaristoon. Vuonna 2021 tämä unelma toteutui Runosaaressa, joka jatkuu nyt vuosittaisena tapahtumana Naantalin saaristossa.', 'Voimallisten näkyjen, rytmin ja mielen liikkeiden tarkentamisen taiturina tunnettu Vuorinen julkaisi viidennen runokokoelmansa Myöhempien kesien jumalat, Los dioses de los veranos ulteriores vuoden 2022 Runosaaressa. Teoksessa Vuorinen kutoo yhteen ihmisen, luonnonvoimat ja kaiken yllä valvovan taivaan Andien ikiaikaisissa maisemissa. Latinalainen Amerikka ja espanjan kieli ovat Vuoriselle erityisen merkityksellisiä, mitä ilmentää kokoelman julkaiseminen samoissa kansissa kaksikielisenä: suomeksi ja espanjaksi (käännös: Zoila Forss-Crespo Moreyra).'], id: 'katariina_vuorinen' },
{ name: 'Juha Kulmala + Positroninen runo-orkesteri', paragraphs: ['Juha Kulmala + Positroninen runo-orkesteri tuuttaa runoutta ja musiikkia herkästi ja häpeilemättä. Rock, blues, jazz, beat, latino, afro, länsirannikko, itärannikko, ulko- ja sisäavaruus, underground, rautalanka, painevasara, sydänääni, suven kimmellys. Meiltä saa kaiken.', 'Juha Kulmala, tekstit.', 'Pekka Tolonen, rytmit, kitarat, bassot, koskettimet ja muut soittimet.'], id: 'juha_kulmala' },
{ name: 'Juha Rautio', paragraphs: ['Juha Rautio (s.1980) on kirjoittanut seitsemän runokokoelmaa, joista viimeisin Jokainen epäilys ennen tätä ja tämän jälkeen ilmestyi 2024 alkuvuodesta. Rautio on esiintynyt aktiivisesti runoilijana vuodesta 2005. Runosaaressa hän esiintyy pitkästä aikaa akustisen kitaran kanssa.'], id: 'juha_rautio' },
{ name: 'Risto Oikarinen', paragraphs: ['Risto Oikarinen on palkittu kirjailija ja saksofonisti. Hänen viimeisin runokokoelmansa on Kiitos tästä yöstä (Otava 2023). Oikarinen yhdistää esityksissään runoutta ja saksofoninsoittoa. Hän on esiintynyt useilla kirjallisuusfestivaaleilla niin kotimaassa kuin Euroopassa, ja hänen runojaan on käännetty kymmenelle kielelle.', 'Oikarinen opettaa kirjoittamista mm. Kriittisessä korkeakoulussa. Hänet on myös vihitty Suomen luterilaisen kirkon pastoriksi.'], id: 'risto_oikarinen' },
{ name: 'Emmi Ketonen', paragraphs: ['Emmi Ketonen on turkulainen suomentaja, joka on kääntänyt erityisesti latinalaisamerikkalaista kirjallisuutta. Vuonna 2017 julkaistiin suomennos chileläisen Vicente Huidobron runoteoksesta Altazor. Vuonna 2025 on tulossa seuraava runosuomennos, valikoima argentiinalaisen Alejandra Pizarnikin tuotannosta. Molempien teosten kustantaja on Kustannusliike Parkko.'], id: 'emmi_ketonen' },
];
export default Performers;

View File

@@ -1,21 +0,0 @@
import type Performer from '../../types/Performer';
const Performers: Array<Performer> = [
{ name: 'Kauko Röyhkä & Severi Pyysalo', paragraphs: ['Kauko Röyhkän ja Severi Pyysalon epätodennäköinen duo on musisoinut yhdessä jo 15 vuotta. Kaksikko on levyttänyt lp:n Turmion suurherttua (Svart 2017). Keikkasetti koostuu enimmikseen Kauko Röyhkän tunnetuimmista lauluista, joihin Severi Pyysalon vibrafoni lisää taidokkaan jazzkuorrutuksen.'], id: 'royhka-pyysalo' },
{ name: 'Uhrijuhla', paragraphs: ['Laulaja Olga Välimaan lämmin ääni johdattaa kuulijan unenomaiseen toiseuteen. Uhrijuhla-yhtye on levyttänyt kaksi albumillista runollista ja melodisesti rikasta musiikkia, jollaista nykyään kuulee enää harvoin. '], id: 'uhrijuhla' },
{ name: 'Juha Kulmala + Positroninen Runo-orkesteri!', paragraphs: ['Juha Kulmala + Positroninen Runo-orkesteri on lyyrinen ufo, jonka ohjaimia vääntävät runoilija Juha Kulmala ja muusikko Pekka Tolonen. Tulemme Runosaareen nyt jo viidettä kertaa ja setissä on jälleen uutta ja ajatonta, kaunista ja purevaa. Runoutta ja sähköistä musiikkia.', 'Juha Kulmala on turkulainen runoilija, jolta on julkaistu 6 kokoelmaa, niistä viimeisin on RESET (Poesia 2022). Jarkko Laine -kirjallisuuspalkinto 2011, Tanssiva karhu -runopalkinto 2014, Wsoy:n kirjallisuussäätiön tunnustuspalkinto 2022. ”Juha Kulmala on ehkä Suomen luotettavin runoilija, mikä ei tarkoita, että hän olisi tylsä.” (Vesa Rantama, Keskisuomalainen)', 'Pekka Tolonen on monitaitoinen muusikko, joka on tehnyt yhteistyötä Kulmalan ja muidenkin runoilijoiden kanssa eri kokoonpanoissa jo toistakymmentä vuotta. '], id: 'kulmala' },
{ name: 'Santtu Puukka', paragraphs: ['Santtu Puukka (s.1972) on Vantaalainen kirjailija. Hänen viides runokokoelma ilmestyy syksyksi Enostonen julkaisemana.'], id: 'puukka' },
{ name: 'Maaria Päivinen', paragraphs: ['Maaria Päivinen on Tohmajärvellä syntynyt, nykyisin Kotkassa asuva kirjailija. Häneltä on ilmestynyt kaksi runokokoelmaa, joista uusin, Maailmanymmärrysmatka (Aviador 2024), sukeltaa maailman lisäksi ihmiseen itseensä. Päivinen rakastaa sanoja, niiden muodostamaa virtaa ja runoutta ylipäänsä.'], id: 'paivinen' },
{ name: 'Henriikka Tavi', paragraphs: ['Henriikka Tavi on runoilija ja kirjailija, jonka tuotantoa on luonnehdittu kokeelliseksi, leikkisäksi ja kielitietoiseksi. Halu venyttää kirjallisuuden rajoja sekä kysymys kirjallisuuden merkityksestä motivoi Tavia kirjoittajana. Tavi on julkaissut lukuisia runoteoksia, joista viimeisimmät ovat Remu (Teos, 2023) ja Pinnan alla -epälibretto (Poesiavihkot/ Poesia 2023). Tavi opettaa kirjoittamista mm. Kriittisessä korkeakoulussa ja on Osuuskunta Poesian aktiivinen jäsen. Hän on saanut teoksistaan paljon tunnustusta ja useita palkintoja.'], id: 'henriikka' },
{ name: 'Jaakko Martikainen ja Henriikka Tavi', paragraphs: ['Jaakko Martikaisen ja Henriikka Tavin osin käsikirjoitetut ja osin improvisoidut esitykset liikkuvat musiikin, runouden ja äänirunouden välimaastossa joka kerta erilaisin painotuksin. Jaakko Martikainen on turkulainen jazzmuusikko ja soiton opettaja. Henriikka Tavi on runoilija, kirjailija ja musiikin intohimoinen harrastaja. '], id: 'jaakko-henriikka' },
{ name: 'Pegasos', paragraphs: ['Pegasos on helsinkiläinen, v. 2015 perustettu kuuden muusikon yhtye, jonka musiikki on helmeilevä ja uniikki yhdistelmä suomenkielistä folkia, popia ja rockia. Yhtyeen tavaramerkiksi muodostunutta, kahden laulajan hiottua stemmalaulua on verrattu niin ruotsalaiseen First Aid Kitiin kuin kotimaisiin Ultra Brahan ja Scandinavian Music Groupiin. Pegasosta on kiitetty tarkkanäköisistä sanoituksistaan ja vaikuttavista keikoistaan, joissa laulajien rehellinen läsnäolo, soundi ja soittajien ilmaisuvoima vetävät kuulijoita puoleensa poikkeuksellisella tavalla.', 'Pegasoksen toinen pitkäsoitto Ei mikään ole niin kuin eilen julkaistiin keväällä 2023. Yhtyeeltä on lisäksi ilmestynyt albumi Anna vielä aikaa (2020), omakustanne-EP (2017), sekä Pepe Willbergin kanssa toteutettu cover-versio Egotrippi-yhtyeen kappaleesta Varovasti nyt (2022). Tällä hetkellä Pegasos työstää 3. albumiaan.', 'Runosaaressa yhtye esiintyy duona lauluntekijä Tuulikki Blom sekä kitaristi Veikki Virkajärven voimin.'], id: 'pegasos' },
{ name: 'Peter Mickwitz ', paragraphs: ['Runoilija Peter Mickwitz on syntynyt vuonna 1964. Hän kirjoittaa myös esseitä ja lyhyttä proosaa. Mickwitzille on myönnetty mm. Ylen Tanssiva Karhu -palkinto sekä runoilijana että kääntäjänä. Vuonna 2024 hän sai Runeberg-palkinnon kokoelmastaan Misslyckad i en uggla. Vuonna 2016 ilmestyi suomeksi valikoima Lyhytproosaa se mikä avautuu Kristiina Lähteen kääntämänä.'], id: 'mickwitz' },
{ name: 'Panu Hämeenaho', paragraphs: ['Panu Hämeenaho on opetellut olemaan sarjakuvapiirtäjä, kirjoittaja ja kirjallisuuden opettaja. Okkultti tulee itsestään.'], id: 'panu' },
{ name: 'Silja Järventausta', paragraphs: ['Silja Järventausta on helsinkiläinen runoilija, kotoisin Seinäjoelta. Häneltä on ilmestynyt seitsemän runokokoelmaa Teokselta, viimeisin, Vuorosana pihapiirissä, tammikuussa 2025. Iltapäivä isolla kirjaimella sai Nihil Interitin vuoden 2022 parhaan runoteoksen palkinnon ja lukuisia ehdokkuuksia. Esikoisteos Patjalla meren yli ilmestyi vuonna 2006.'], id: 'jarventausta' },
{ name: 'Katariina Vuorinen', paragraphs: ['Katariina Vuorinen on maailmassa elävä runoilija, @apoetontheroadandintothewild, joka viettää pohjoisen valoisat ajat meren äärellä Velkuanmaan saaressa, ja pimeät kuut Chilen Andeilla ja Valparaísossa, kiehtovimmassa kaupungissa. Tuntemattomien seutujen koluaminen on hänelle elinehto.', 'Vuorisen kuudes runokokoelma, Kesän oraakkeli (Aviador 2025) julkaistaan tämän vuoden Runosaaressa. Runosaari on Vuorisen Naantalin saaristoon luoma korkeatasoisen runouden ja musiikin jokakesäinen, moniääninen juhla. Se sai alkunsa, kun hän löysi nomadivuosiensa keskeltä maagisen Velkuanmaan saaren, ja tiesi heti paikan kutsuvan runon henkiä saaristoon.', 'Vuorinen on kiitetty esiintyjä sekä yksin että muusikoiden kanssa Suomessa ja ulkomailla, ja hänen runojaan on käännetty neljälletoista kielelle. Vuorisen edellinen teos, Myöhempien kesien jumalat, Los dioses de los veranos ulteriores (Aviador 2022) julkaistiin kaksikielisenä laitoksena, suomeksi ja espanjaksi. Sen aistivoimaisen tarkka ja vuolas runous on hurmannut yleisöjä etenkin Latinalaisessa Amerikassa.'], id: 'katariina' },
{ name: 'Milagros Corcuera', paragraphs: ["Milagros Corcuera (Buenos Aires, 1993) is an Argentine writer whose poetry intertwines the personal with the universal. Her work explores themes of memory, longing, identity, and human experience with a delicate yet striking voice, drawing on Latin America's rich traditions, folklore, nature, and fascination with diverse cultures. She has published Trasandina (Valparaíso, 2018), Una pared llena de exvotos (Bs As, 2022) and Cabinet of Curiosities (Bs As, 2023), the children's book El Caleidoscopio (Bs As, 2024) as well as a compilation of Bilingual poems in Spanish-English (Denmark, 2025). Her poetry delves into the subtle beauty of everyday moments and distant objects from different eras. She has performed at festivals in Chile, México, Denmark, and Argentina, won multiple awards, and been featured in various anthologies. Currently, she is developing projects in nonfiction, travel writing, poetry, and children's literature."], id: 'milagros' },
{ name: 'Tiina Lehikoinen', paragraphs: ['Tiina Lehikoinen on kirjailija ja kuvataiteilija, joka viihtyy lajien välisillä rajoilla. Hänen uusin teoksensa Mutta armo on kukka joka laulaa (Poesia) ilmestyi keväällä 2024. Lehikoisen kaunokirjallinen tuotanto sisältää useita runo- ja novellikokoelmia sekä esseihtivän romaanin. Kirjoissaan hän on käsitellyt ekofeministisiä teemoja, kielen suhdetta ruumiillisuuteen, erilaisia valtasuhteita ja ympäristöhuolta sekä leikin, mielikuvituksen ja toivon merkitystä kulttuuristen eläinten eloonjäämisessä. Lehikoisen teoksille on myönnetty Vuoden aforismikirja - ja Tampereen kaupungin kirjallisuuspalkinto ja lisäksi ne ovat olleet Runeberg-, Tanssiva Karhu -, Nihil Interit - ja Tiiliskivi-palkintoehdokkaana. Koulutukseltaan Lehikoinen on filosofian ja taiteen maisteri. Kaunokirjallisen ja taiteellisen työnsä ohella hän on päätoimittanut runouslehti Tuli&Savua ja verkkolehti Noesista sekä opettanut luovaa kirjoittamista vuodesta 2005. Lehikoisen tekstejä on käännetty englanniksi, espanjaksi, italiaksi, venäjäksi ja saksaksi.'], id: 'lehikoinen' },
//{ name: '', paragraphs: [''], id: 'placeholder' },
];
export default Performers;

View File

@@ -1,140 +0,0 @@
import type Performer from "../../types/Performer";
const Performers: Array<Performer> = [
{
name: "Olli Sinivaara",
paragraphs: [
"Olli Sinivaara (s. 1980) on palkittu ja arvostettu runoilija. Hänen kuudes runokokoelmansa Puut (2021) voitti Ylen Tanssiva karhu -runopalkinnon.",
" Aiemmin Sinivaara on voittanut muun muassa Kalevi Jäntin palkinnon vuonna 2007 ilmestyneellä runokokoelmallaan Palava maa.",
"Sinivaaran runoja on julkaistu monilla kielillä, mm. englanniksi, ranskaksi, saksaksi ja italiaksi. Sinivaara on myös suomentanut ranskalaista filosofiaa ja runoutta.",
" Kuva: Liisa Takala",
],
id: "sinivaara",
},
{
name: "Laakso ja Siljamäki",
paragraphs: [
"Punainen aistikirja, dionyysisiä muistiinpanoja on vimmainen päiväkirjaromaani, armoton transkriptio kirjailijan ja klovnin rakkaussuhteesta, joka sytyttää roihuun muistikirjan. Kirjailija Laura Laakson ja klovni-kuvittaja-muusikko Dodo Siljamäen yhteisteos piehtaroi hurman ja haikean ikiaikaisella sirkusareenalla ja mouruaa hyväillen taiteidenvälistä hellää.",
],
id: "laakso_siljamaki",
},
{
name: "Juurakko",
paragraphs: [
"Väkevää tarinankerrontaa ja juurimusiikkia yhdistelevä Juurakko puhkuu yhteisöllistä ja maanläheistä tunnelmaa. Yhtye risteyttää suomenkielisen blueslaulannan ja perinteisen kotimaisen soittimiston raikkaalla skiffle-asenteella eikä kaihda eriskummallisiakaan tarinoita. Rouhea Juurakko-blues vie ajoittain syvälle rämeelle ja toisinaan tanssittaa kepeästi laivan kannella. ",
"Juurakko valittiin Vuoden Artistiksi vuoden 2020 Etnogaalassa. Yhtye on julkaissut neljä studioalbumia sekä kuunnelmallisen Juurimultaa-podcastsarjan. Kansainvälisesti keikkailevaa bändiä on kiitelty omintakeisen musiikkityylinsä lisäksi lavalta säteilevästä positiivisesta energiasta.",
"HIGHLIGHTS:",
"TALLINN MUSIC WEEK 2025 (showcase), FESTIVAL LES TRAVERSÉES TATIHOU (FR) 2019, KORRÖ FOLKMUSIKFESTIVAL (SE) 2022, FIGURA FESTSPIELE (DK) 2019/2024, SaltFest, Kaustinen Folk Music Festival, Puistoblues, G Livelab, Haapavesi Folk, Tampereen sävel, Kalott JazzBlues",
"JUURAKKO:",
"LAURA KAARTINEN - laulu, matkaharmoni, lyömäsoittimet",
"EIJA KANKAANRANTA - kanteleet",
"KAISA SAARIKORPI - laulu, sikarilaatikkosoittimet, kitarat, lyömäsoittimet",
"MINSKU TAMMELA - laulu, jouhikko, kampa, munniharppu, lyömäsoittimet",
"ANNA WIKSTEN - laulu, plankku, lyömäsoittimet",
"MYYRI SYSIVESI - miksaus",
],
id: "juurakko",
},
{
name: "Saila Susiluoto",
paragraphs: [
"Saila Susiluoto (s. 1971) on Perniössä asuva kirjailija. Hän on julkaissut useita runoteoksia, romaanin, Antikytheran-iPad-sovelluksen sekä auditiivisen taideteoksen Oratorio. Susiluoto on palkittu Kalevi Jäntin palkinnolla, Suomi-palkinnolla ja Einari Vuorela -runopalkinnolla. Carmen oli Pohjoismaiden neuvoston kirjallisuuspalkintoehdokkaana vuonna 2012. Vuonna 2024 ilmestyi kiitetty Akheron-runokokoelma ja vuonna 2025 runoteos Rituaali (Bokeh). Susiluodon runoja on käännetty viidelletoista kielelle.",
],
id: "susiluoto",
},
{
name: "Markku Pääskynen",
paragraphs: [
"Markku Pääskynen (s. 1973) on Helsingissä asuva kirjailija. Hän on koulutukseltaan filosofian maisteri ja julkaissut romaaneja, novelleja ja esseitä. Lisäksi hän on suomentanut lyriikkaa mm. nykykreikasta.",
"Pääskynen on soittanut ud-luuttua jo yli kaksi vuosikymmentä.",
"Kuva: Saila Susiluoto",
],
id: "paaskynen",
},
{
name: "Pegasos (Trio)",
paragraphs: [
"Pegasos on helsinkiläinen 6 muusikon yhtye, joka yhdistelee musiikissaan indiefolkia, -popia ja -rockia. Vuonna 2015 alkunsa saaneen yhtyeen soundi perustuu kahden laulajan kehuja niittäneisiin harmonioihin, jotka taipuvat niin herkkyyteen kuin nostattavaan voimallisuuteen. Pegasosta on kiitetty poikkeuksellisen tarkkanäköisistä lyriikoista ja keikoista, joilla yhtye hurmaa kuulijan vilpittömillä spiikeillään ja värikylläisellä soinnillaan.",
"Yhtyeen kolmas pitkäsoitto Hyvä noita näki päivänvalon maaliskuussa 2026. Erilaisuutta ja normien rikkomista juhlistava konseptialbumi herätti yleisön kiinnostuksen jo singleillään, keräten ylistystä somessa sekä soittoa Radio Suomessa ja Radio Helsingissä. Radio Suomen Levylautakunnan lähes täysin pistein voittanutta progressiivista folkrock-teosta Toivon kuvia on luonnehdittu mm. ”taideteokseksi” ja ”rohkeiden valintojen ja tekojen” kappaleeksi, jossa on ”järisyttävän hyvä kertsi”.",
"Runosaaressa Pegasos esittää triona riisuttuja versioita Hyvä noita-albumilta.",
],
id: "pegasos",
},
{
name: "Helena Sinervo",
paragraphs: [
"Helmikuussa ilmestynyt Tiikerin tehtävät on Helena Sinervon 13. runoteos. Runojen lisäksi hän on kirjoittanut romaaneja, esseitä ja lastenkirjoja sekä suomentanut runoutta. Sinervolle on myönnetty Finlandia-palkinto ja Aleksis Kiven rahaston palkinto sekä kahdesti Tanssiva karhu. Hän on taiteilijaprofessori, ja hänen runouttaan on käännetty yli 30 kielelle.",
],
id: "helena-sinervo",
},
{
name: "Olli Heikkonen",
paragraphs: [
"Olli Heikkonen on Helsingissä asuva runoilija, jolta on julkaistu seitsemän kokoelmaa. Niistä viimeinen Hallitut vallat (Teos) ilmestyi syksyllä 2025. Lisäksi hän on kääntänyt ja toimittanut liiviläisen nykyrunouden antologian Kerran olin taivaan suolajärvi (Aviador, 2022).",
],
id: "olli-heikkonen",
},
{
name: "Häivä",
paragraphs: [
"Häivä on genrerajoja rikkova poeettinen äänimatka, joka yhdistää omaperäisellä tavalla live-elektroniikkaa, kitaraa ja ihmisen ääntä. Häivä on värisevä tila, jossa ääni, valo, hiljaisuus ja varjot punoutuvat yhteen vieden kuulijan itsensä läpäisevälle matkalle. Se puhuttelee aistimusten ja tunteiden kielellä ja pysähdyttää, kiihdyttää, pitää otteessaan ja tarvittaessa päästää irti.",
"Guitar and live electronics, Matti Salo",
"Vocals, Riia Muurimaa",
],
id: "haiva",
},
{
name: "Jouni Inkala",
paragraphs: [
"Jouni Inkala syntyi 1966 ja on julkaiseva poeetta vuodesta 1992. Viidentoista runoteoksen lisäksi hän on kirjoittanut draamaa niin radioon kuin näyttämölle. J.H. Erkon esikoiskirjapalkinnon (1992) sekä Einari Vuorela -runopalkinnon (2005) lisäksi hän sai Kalevi Saxell -runopalkinnon hopeapalkinnon vuonna 2024. Häneltä ovat ilmestyneet valitut runot sekä italiaksi että kahdesti saksaksi. Runovierailuja ulkomailla Inkalalle on kertynyt tähän mennessä kolmekymmentäkuusi, viimeisimmät Roomaan ja Genovaan vuonna 2024.",
"Vuonna 2006 Inkala sisällytettiin Routledge-kustantamon toimittamaan (Taylor & Francis Group. London and New York) INTERNATIONAL WHO´S WHO IN POETRY -hakuteokseen.",
],
id: "jouni-inkala",
},
{
name: "Juha Kulmala & Jumbo",
paragraphs: [
"Juha Kulmala & Jumbo! yhdistää runoa ja soittoa sähköisesti ja ilman kaavaa. Alkuperäinen Jumbohan oli sudanilainen elefantti, me olemme lyyrisen savannin modernit törisijät.",
"Kokoonpano on esiintynyt monilla eri nimillä ja säädöillä, tekemisen ytimessä on kuitenkin ollut aina sanan mahti, avaruuden valloitus ja boom boom boom.",
],
id: "kulmala",
},
{
name: "Outi-Illuusia Parviainen",
paragraphs: [
"Lavarunoilija Outi-Illuusia Parviaisen runot ovat rytmisiä ja värikkäitä. Niissä pysähdytään katoavan hetken yksityiskohtiin, toisen ihmisen äärelle, suuriin tunteisiin ja yksinäisyyteen. Lavalla Parviainen päästää sanat valloilleen ja juopuu läsnäolosta yhdessä yleisön kanssa.",
"Hän on julkaissut neljä runoteosta ja kirjoittaa parhaillaan viidettä.",
"Viimeisin teos Olen niitty, odotan (Aviador, 2025) käsitteli tahatonta lapsettomuutta ja se nähtiin myös näyttämöteoksena. Runosaaressa taas kuullaan tarttuvia tekstejä ihmisen sisimmän tiheydestä ja rakkauden kitkeryydestä. ",
],
id: "outi-illuusia",
},
{
name: "Katariina Vuorinen",
paragraphs: [
"Katariina Vuorinen on maailmassa elävä runoilija, joka viettää pohjoisen valoisat ajat meren saaressa Velkualla, ja pimeät kuut Chilen Andeilla sekä Valparaísossa, kiehtovimmassa kaupungissa. Tuntemattomien seutujen koluaminen on hänelle elinehto.",
"Vuonna 2018 hän löysi nomadivuosiensa keskeltä maagisen Velkuanmaan saaren, ja tiesi heti paikan kutsuvan runon henkiä saaristoon. Vuonna 2021 unelma toteutui ja hän loi Runosaaren, joka jatkuu nyt vuosittaisena tapahtumana Naantalin saaristossa.",
"Voimallisten näkyjen, rytmin ja mielen liikkeiden tarkentamisen taiturina tunnettu Vuorinen on julkaissut muiden teosten ohella kuusi runokokoelmaa, joista viimeisin, Kesän oraakkeli (Aviador), ilmestyi 2025.",
"Vuorisen edellinen teos, Myöhempien kesien jumalat, Los dioses de los veranos ulteriores (Aviador, 2022) julkaistiin kaksikielisenä laitoksena, suomeksi ja espanjaksi. Sen aistivoimaisen tarkka ja vuolas runous on hurmannut yleisöjä etenkin Latinalaisessa Amerikassa.",
"Maailmassa Vuorisen runoja voi lukea 14 kielellä.",
],
id: "katariina-vuorinen",
},
{
name: "Zoila",
paragraphs: [
"Zoila Forss-Crespo Moreyra on perulaissyntyinen suomalainen runoilija ja kääntäjä. Hän on julkaissut runokirjat ”Revontuli”, ”Syytön harppuuna” ja ”Eleonor y otras hierbas” (suom. Eleonor-ja-muut-yrtit), ja toimittanut runoantologian ”Hologrammi”. Hän sai Nihil Interitin Runoteko-palkinnon vuonna 2023 Turun kirjamessuilla. Forssin runoja on julkaistu eri kirjallisuuslehdissä ja antologioissa, kuten monikielisessä Sulavassa (Suomen PEN-Finnish PEN 2021) ja osana maailmanlaajuisen käännösrunouden teoskokonaisuutta Purple Ink (Language and Literature departments of Brown University, USA).",
"Hän kääntää erityisesti runoutta ja proosaa.",
],
id: "zoila",
},
{
name: "Djangomania",
paragraphs: [
"Djangomania on viulisti-laulaja Arto Nybomin, kontrabasisti Kari Korpisen, haitaristi Johannes Niskasen ja kitaristi Vesa Tompurin muodostama jazzyhtye. Runosaareen yhtye tulee Nybomin ja Tompurin muodostamana duona.",
],
id: "djangomania",
},
//{ name: '', paragraphs: [''], id: 'placeholder' },
];
export default Performers;

4
declarations.d.ts vendored
View File

@@ -1,4 +0,0 @@
declare module "*.module.scss" {
const classes: { [key: string]: string };
export default classes;
}

View File

@@ -1,25 +0,0 @@
<!DOCTYPE html>
<html lang="fi">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<title>Runosaari</title>
<link
href="https://fonts.googleapis.com/css?family=Crimson+Text&display=optional"
rel="stylesheet"
/>
<meta property="og:title" content="Runosaari" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.runosaari.fi/" />
<meta property="og:image:url" content="https://www.runosaari.fi/runosaari-logo.jpg" />
<meta property="og:image:type" content="image/jpg" />
<meta property="og:image:width" content="1516" />
<meta property="og:image:height" content="582" />
<meta property="og:description" content="Runofestivaali saariston sylissä 12. - 13.6.2026" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@@ -1,22 +0,0 @@
set shell := ["bash", "-eu", "-o", "pipefail", "-c"]
default:
@just --list
install:
bun install
dev:
bun run dev
build:
bun run build
start:
bun run start
lint:
bun run lint
deploy:
bash scripts/deploy.sh

5
next-env.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

6
next.config.js Normal file
View File

@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}
module.exports = nextConfig

5416
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,26 +3,27 @@
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"start": "vite preview",
"lint": "tsc --noEmit"
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"next": "12.1.6",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-icons": "^4.4.0",
"react-router-dom": "^6.22.0",
"react-transition-group": "^4.4.2",
"reactstrap": "^9.1.1",
"sass": "^1.101.0"
"sass": "^1.52.2"
},
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/node": "17.0.40",
"@types/react": "18.0.11",
"@types/react-dom": "18.0.5",
"@types/react-transition-group": "^4.4.4",
"@vitejs/plugin-react": "^4.2.0",
"typescript": "^5.3.0",
"vite": "^5.1.0"
"eslint": "8.17.0",
"eslint-config-next": "12.1.6",
"typescript": "4.7.3"
}
}

26
pages/_app.tsx Normal file
View File

@@ -0,0 +1,26 @@
import '../styles/globals.scss';
import '../styles/transitions.scss';
import type { AppProps } from 'next/app';
import Footer from './components/Footer';
import NavBar from './components/NavBar';
import Logo from './components/Logo';
import Head from 'next/head';
function Runosaari({ Component, pageProps }: AppProps) {
return (
<>
<Head>
<title>Runosaari</title>
</Head>
{/* <NavBar /> */}
<Logo />
<main>
<Component {...pageProps} />
</main>
{/* <NavBar /> */}
<Footer />
</>
);
}
export default Runosaari;

36
pages/_document.tsx Normal file
View File

@@ -0,0 +1,36 @@
import Document, { Html, Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link
href='https://fonts.googleapis.com/css?family=Crimson+Text'
rel='stylesheet'
/>
<meta property="og:title" content="Runosaari" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.runosaari.net/" />
<meta property="og:image:url" content="https://www.runosaari.net/runosaari-logo.jpg" />
<meta property="og:image:type" content="image/jpg" />
<meta property="og:image:width" content="1516" />
<meta property="og:image:height" content="582" />
<meta property="og:description" content="Runosaari 7. ja 14.6. Naantalin saaristo. Vuonna 2024 saarifestivaali tuo runoutta ja musiikkia kahteen kesäkuun perjantaihin" />
<script
async
defer
data-website-id='3fb34a0a-f153-4941-9fa4-16c6b648b055'
src='https://umami.avislacus.com/umami.js'
></script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;

229
pages/arkisto.tsx Normal file
View File

@@ -0,0 +1,229 @@
import React, { useEffect, useState } from 'react';
import Image from 'next/image';
import { CSSTransition } from 'react-transition-group';
import shared from '../styles/Shared.module.scss';
import styles from '../styles/Archive.module.scss';
import PerformersData2021 from '../data/performers/2021';
import PerformersData2022 from '../data/performers/2022';
import PerformersData2023 from '../data/performers/2023';
import Performer from '../types/Performer';
import { BiChevronDown, BiChevronLeft } from 'react-icons/bi';
interface PerformerCard extends Performer {
showDesc: boolean;
}
const Archive = () => {
const [performers2021, setPerformers2021] = useState<PerformerCard[]>([]);
const [performers2022, setPerformers2022] = useState<PerformerCard[]>([]);
const [performers2023, setPerformers2023] = useState<PerformerCard[]>([]);
useEffect(() => {
let cards: PerformerCard[] = [];
PerformersData2021.map((p) => {
let newCard = { ...p, showDesc: false };
cards.push(newCard);
});
setPerformers2021(cards);
}, []);
useEffect(() => {
let cards: PerformerCard[] = [];
PerformersData2022.map((p) => {
let newCard = { ...p, showDesc: false };
cards.push(newCard);
});
setPerformers2022(cards);
}, []);
useEffect(() => {
let cards: PerformerCard[] = [];
PerformersData2023.map((p) => {
let newCard = { ...p, showDesc: false };
cards.push(newCard);
});
setPerformers2023(cards);
}, []);
const togglePerformerDesc2021 = (id: string) => {
let updated: PerformerCard[];
updated = performers2021.map((p) => {
if (p.id === id) {
p.showDesc = !p.showDesc;
}
return p;
});
setPerformers2021(updated);
};
const togglePerformerDesc2022 = (id: string) => {
let updated: PerformerCard[];
updated = performers2022.map((p) => {
if (p.id === id) {
p.showDesc = !p.showDesc;
}
return p;
});
setPerformers2022(updated);
};
const togglePerformerDesc2023 = (id: string) => {
let updated: PerformerCard[];
updated = performers2023.map((p) => {
if (p.id === id) {
p.showDesc = !p.showDesc;
}
return p;
});
setPerformers2023(updated);
};
return (
<section className={shared.page + ' ' + styles.archivePage}>
<h1>Arkisto</h1>
<h2 className={styles.year}>2023</h2>
{performers2023.map((p) => (
<div className={styles.performerContainer} key={p.id}>
<Image
className={styles.performerImage}
src={'/performers/2023/' + p.id + '.jpg'}
width={100}
height={100}
layout='fixed'
alt={p.name}
/>
<div className={styles.performerTextContainer}>
<div
className={styles.performerTitle}
onClick={() => togglePerformerDesc2023(p.id)}
>
<h2>{p.name}</h2>
<button className={shared.openingChevron}>
{p.showDesc ? (
<BiChevronDown size='3rem' />
) : (
<BiChevronLeft size='3rem' />
)}
</button>
</div>
<CSSTransition
in={p.showDesc}
timeout={1000}
classNames='fadeTransition'
>
{p.showDesc ? (
<div>
{p.paragraphs.map((parag, index) => (
<p key={index}>{parag.toString()}</p>
))}
</div>
) : (
<span></span>
)}
</CSSTransition>
<hr />
</div>
</div>
))}
<h2 className={styles.year}>2022</h2>
{performers2022.map((p) => (
<div className={styles.performerContainer} key={p.id}>
<Image
className={styles.performerImage}
src={'/performers/2022/' + p.id + '.jpg'}
width={100}
height={100}
layout='fixed'
alt={p.name}
/>
<div className={styles.performerTextContainer}>
<div
className={styles.performerTitle}
onClick={() => togglePerformerDesc2022(p.id)}
>
<h2>{p.name}</h2>
<button className={shared.openingChevron}>
{p.showDesc ? (
<BiChevronDown size='3rem' />
) : (
<BiChevronLeft size='3rem' />
)}
</button>
</div>
<CSSTransition
in={p.showDesc}
timeout={1000}
classNames='fadeTransition'
>
{p.showDesc ? (
<div>
{p.paragraphs.map((parag, index) => (
<p key={index}>{parag.toString()}</p>
))}
</div>
) : (
<span></span>
)}
</CSSTransition>
<hr />
</div>
</div>
))}
<h2 className={styles.year}>2021</h2>
{performers2021.map((p) => (
<div className={styles.performerContainer} key={p.id}>
<Image
className={styles.performerImage}
src={'/performers/2021/' + p.id + '.jpg'}
width={100}
height={100}
layout='fixed'
alt={p.name}
/>
<div className={styles.performerTextContainer}>
<div
className={styles.performerTitle}
onClick={() => togglePerformerDesc2021(p.id)}
>
<h2>{p.name}</h2>
<button className={shared.openingChevron}>
{p.showDesc ? (
<BiChevronDown size='3rem' />
) : (
<BiChevronLeft size='3rem' />
)}
</button>
</div>
<CSSTransition
in={p.showDesc}
timeout={1000}
classNames='fadeTransition'
>
{p.showDesc ? (
<div>
{p.paragraphs.map((parag, index) => (
<p key={index}>{parag.toString()}</p>
))}
</div>
) : (
<span></span>
)}
</CSSTransition>
<hr />
</div>
</div>
))}
</section>
);
};
export default Archive;

View File

@@ -0,0 +1,28 @@
import React from 'react';
import styles from '../../styles/Collaboration.module.scss';
const Collaboration = () => {
return (
<>
<h1>Yhteistyössä</h1>
<div className={styles.collabContainer}>
<span>Runoviikko Ry</span>
<div className={styles.collabLogoRow}>
<img
className={styles.collabLogo}
src='/collaborators/kirjan_talo.png'
alt='kirjan talo logo'
/>
</div>
<span>Velkuan saaristolaisyhdistys ry</span>
<span>Cafe Laituri</span>
<span>Saaristohotelli Vaihela</span>
<span>Aviador Kustannus</span>
<span>Enostone Kustannus</span>
<span>Keski-Suomen kirjailijat</span>
</div>
</>
);
};
export default Collaboration;

View File

@@ -1,4 +1,5 @@
import { Link } from 'react-router-dom';
import Link from 'next/link';
import Image from 'next/image';
import React from 'react';
import styles from '../../styles/Footer.module.scss';
@@ -13,7 +14,7 @@ const Footer = () => {
<br />
</div>
<div className={styles.middle}>
<Link to='/#nav-bar'>
<Link href='/#nav-bar'>
<img
className={styles.logo}
src='/small-logo.png'
@@ -22,10 +23,12 @@ const Footer = () => {
</Link>
<div>
<a
href='https://gitea.tietokonepaja.fi/tietokonepaja/runosaari'
className={styles.sourceLink}
href='https://github.com/codevictory/runosaari.net'
>
lähdekoodi
</a> by <a href='https://tietokonepaja.fi'>Livonsaaren Tietokonepaja</a>
</a>
by codevictory
</div>
</div>
<div className={styles.right}>

33
pages/components/Lead.tsx Normal file
View File

@@ -0,0 +1,33 @@
import React from 'react';
import styles from '../../styles/Lead.module.scss';
const Lead = () => {
return (
<div className={styles.leadContainer}>
<h2 className={styles.leadTitle}>
<span className={styles.dateAndPlace}>
7. ja 14.6. Naantalin saaristo
</span>
Vuonna 2024 saarifestivaali tuo runoutta ja musiikkia kahteen kesäkuun perjantaihin
</h2>
{/* <p className={styles.leadText}>
Runosaari on poikkitaiteellinen runofestivaali Livonsaaren, Palvan ja
Velkuanmaan saarissa. Festivaali järjestetään kolmatta kertaa
13.—15.6.2024.
</p>
<p className={styles.leadText}>
Tapahtuma kutsuu Naantalin saaristoon joukon valovoimaisia ja
monialaisia taiteen tekijöitä. Ohjelmassa runous yhdistyy elävään
musiikkiin ja erilaisiin taiteellisiin työpajoihin.
</p>
<p className={styles.leadText}>
Lumi ja jää vähenee, vedenpinta nousee ja pandemian aallot viistävät
meidänkin rantojamme. Peurojen kurittaman monimuotoisuuden keskelle
nousee Runosaari ihmettelemään ihmisen ja muun luonnon olemista taiteen
ja ilmaisun keinoin.
</p> */}
</div>
);
};
export default Lead;

39
pages/components/Logo.tsx Normal file
View File

@@ -0,0 +1,39 @@
import React, { useEffect, useState } from 'react';
import styles from '../../styles/Logo.module.scss';
import Link from 'next/link';
const Logo = () => {
const [isDesktop, setIsDesktop] = useState(true);
useEffect(() => {
setIsDesktop(window.innerWidth > 768);
}, []);
return (
<Link href="/">
<a>
<section className={styles.logoContainer}>
<div className={styles.logo} id='logo-start'>
<picture>
<source
srcSet='/runosaari-logo_small.jpg'
media='(max-width: 600px)'
/>
<source srcSet='/runosaari-logo.jpg' />
<img
src='/runosaari-logo.jpg'
alt='Runosaari logo'
className={styles.logoImage}
/>
</picture>
<div className={styles.logoCredits}>
<div>@Sanna Hukkanen</div>
</div>
</div>
</section>
</a>
</Link>
);
};
export default Logo;

View File

@@ -0,0 +1,37 @@
import Link from 'next/link';
import styles from '../../styles/NavBar.module.scss';
const NavBar = () => {
return (
<>
<div className={styles.navBarContainer}>
<nav className={styles.navBar}>
<Link href='/'>
<a className={styles.navBarLink}>Etusivu</a>
</Link>
<Link href='/program'>
<a className={styles.navBarLink}>Ohjelma</a>
</Link>
<Link href='/performers'>
<a className={styles.navBarLink}>Esiintyjät</a>
</Link>
{/* // No workshops on 2023
<Link href='/workshops'>
<a className={styles.navBarLink}>Työpajat</a>
</Link> */}
<Link href='/info'>
<a className={styles.navBarLink}>Info</a>
</Link>
<Link href='/safety'>
<a className={styles.navBarLink}>Turvallisuus</a>
</Link>
<Link href='/archive'>
<a className={styles.navBarLink}>Arkisto</a>
</Link>
</nav>
</div>
</>
);
};
export default NavBar;

50
pages/esiintyjat/[id].tsx Normal file
View File

@@ -0,0 +1,50 @@
import React, { useEffect, useState } from 'react';
import { useRouter } from 'next/router'
import shared from '../../styles/Shared.module.scss';
import styles from '../../styles/Performer.module.scss';
import PerformersData from '../../data/performers/2024';
import Performer from '../../types/Performer';
import Image from 'next/image';
const PerformerPage = () => {
const router = useRouter()
const [performer, setPerformer] = useState<Performer>({
name: '',
paragraphs: [],
id: ''
});
useEffect(() => {
setPerformer(PerformersData.find(p => p.id === router.query.id) ?? {
name: '',
paragraphs: [],
id: ''
});
}, [router.query.id])
return (
performer.name == '' ?
(<div>Esiintyjää tunnisteella "{router.query.id}" ei löydy.</div>)
: (
<div className={styles.performerContainer}>
<Image
className={styles.performerImage}
src={'/performers/2024/' + performer.id + '.jpg'}
width={300}
height={300}
layout='fixed'
alt={performer.name}
/>
<h2>{performer.name}</h2>
<div>
{performer.paragraphs.map((parag, index) => (
<p key={index}>{parag.toString()}</p>
))}
</div>
</div>
)
);
}
export default PerformerPage;

27
pages/index.tsx Normal file
View File

@@ -0,0 +1,27 @@
import type { NextPage } from 'next';
import Performers from './performers';
import Program from './program';
import Info from './info';
import styles from '../styles/Index.module.scss';
import Lead from './components/Lead';
import Collaboration from './components/Collaboration';
import Workshops from './workshops';
import Archive from './arkisto';
// import Workshops from './workshops';
const Home: NextPage = () => {
return (
<div className={styles.indexContainer}>
<h1>Runosaari</h1>
<Lead />
<Program />
<Performers />
{/* <Workshops /> */}
<Info />
<Collaboration />
{/* <Archive /> */}
</div>
);
};
export default Home;

View File

@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import shared from '../../styles/Shared.module.scss';
import styles from '../../styles/Info.module.scss';
import shared from '../styles/Shared.module.scss';
import styles from '../styles/Info.module.scss';
import { BiChevronDown, BiChevronLeft } from 'react-icons/bi';
import { CSSTransition } from 'react-transition-group';
@@ -82,16 +82,12 @@ const Info = () => {
{infoToggles.bus ? (
<div>
<p>
Bussi 203 lähtee Turusta ma-pe klo 16:10 ja Naantalista klo 17,
ja saapuu Velkuan Teersaloon n. klo 17:45. Tämä on ainoa suora
yhteys festivaalille. Palvan saareen on Teersalosta yksi lossi,
ja Velkuanmaahan kaksi. Lossit lähtevät puolen tunnin välein
(tasatunnein ja puolelta) Teersalosta ja Velkuanmaasta, ja Palvasta
aina varttia vaille ja yli tasatunnin. (Aikataulut:{' '}
<a href="https://www.finferries.fi/">finnferries.fi</a>)
Takaisin päin busseja ei kulje viikonloppuisin.
Bussi 203 lähtee Turusta (Kauppatori E2) ma-pe 16:30 ja saapuu
Velkualle 17:53. Tämä on ainoa suorayhteys festivaali alueelle.
Takaisin päin bussi menee 06:20 Teersalosta ja on 07:37 Turussa
(Kauppatori E2)
</p>
<a href='https://cms.foli.fi/sites/default/files/documents-2024-04/Linja%20200%2C203.pdf'>
<a href='https://www.foli.fi/fi'>
Paikallisliikenteen bussiaikataulut
</a>
</div>

View File

@@ -1,11 +1,12 @@
import Image from 'next/image';
import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import styles from '../../styles/Performers.module.scss';
import shared from '../../styles/Shared.module.scss';
import Performer from '../../types/Performer';
import styles from '../styles/Performers.module.scss';
import shared from '../styles/Shared.module.scss';
import Performer from '../types/Performer';
import { BiChevronDown, BiChevronLeft } from 'react-icons/bi';
import PerformersData from '../../data/performers/2026';
import PerformersData from '../data/performers/2024';
import { CSSTransition } from 'react-transition-group';
import Link from 'next/link';
import { FiExternalLink } from 'react-icons/fi';
interface PerformerCard extends Performer {
@@ -44,12 +45,12 @@ const Performers = () => {
{performers.length !== 0 ? (
performers.map((p) => (
<div className={styles.performerContainer} key={p.id}>
<img
<Image
className={styles.performerImage}
src={'/performers/2026/' + p.id + '.jpg'}
src={'/performers/2024/' + p.id + '.jpg'}
width={100}
height={100}
loading="lazy"
layout='fixed'
alt={p.name + ' image'}
/>
<div className={styles.performerTextContainer}>
@@ -86,11 +87,13 @@ const Performers = () => {
</div>
))
) : (
<i className={shared.moreInfoLaterText}>Lisätietoja tulossa myöhemmin...</i>
<i>Lisätietoja tulossa myöhemmin...</i>
)}
<Link to="/archive">
<Link href="/arkisto">
<a>
<span className={styles.archiveLinkText}>Aiempien vuosien esiintyjiä</span>
<FiExternalLink fontSize={20} />
</a>
</Link>
</section>
);

115
pages/program.tsx Normal file
View File

@@ -0,0 +1,115 @@
import React, { useState } from 'react';
import { FiExternalLink } from 'react-icons/fi';
import shared from '../styles/Shared.module.scss';
import styles from '../styles/Program.module.scss';
import { CSSTransition } from 'react-transition-group';
import { BiChevronDown, BiChevronLeft } from 'react-icons/bi';
import Performer from '../types/Performer';
import Image from 'next/image';
import Link from 'next/link';
interface DayToggles {
wed: boolean;
thu: boolean;
fri: boolean;
sat: boolean;
}
const firstPerformers: Performer[] = [];
const secondPerformers: Performer[] = [];
const Program = () => {
const [firstPerformers] = useState([
{ id: "ayras", name: "Äyräs", paragraphs: [] },
{ id: "hanna_storm", name: "Hanna Storm", paragraphs: [] },
{ id: "juha_rautio", name: "Juha Rautio", paragraphs: [] },
{ id: "katariina_vuorinen", name: "Katariina Vuorinen & Ilkka Turta", paragraphs: [] }]);
const [secondPerformers] = useState([
{ id: "juha_kulmala", name: "Juha Kulmala + Positroninen runo-orkesteri", paragraphs: [] },
{ id: "terhi_forssen", name: "Terhi Forssén", paragraphs: [] },
{ id: "katariina_vuorinen", name: "Katariina Vuorinen & Björn", paragraphs: [] }]);
return (
<section className={shared.page}>
<h1 id='program-start'>Ohjelma</h1>
<div className={styles.eventContainer}>
{/* Vaihela */}
<div className={styles.event}>
<div className={styles.programTitle}>
<span className={styles.timeSpan}>pe</span>
<span className={styles.timeSpan}>7.6.</span>
<span className={styles.timeSpan}>18 - 21</span>
</div>
<h2>
<a href='https://www.cafelaituri.fi'>
<span className={styles.placeName}>Vaihela</span>
<FiExternalLink fontSize={20} />
</a>
</h2>
<div className={styles.performerList}>
{firstPerformers.map((p) => (
<a href={'/esiintyjat/' + p.id} className={styles.performerCard}>
<Image
className={styles.performerImage}
src={'/performers/2024/' + p.id + '.jpg'}
width={80}
height={80}
layout='fixed'
alt={p.name}
/>
<span className={styles.performerName}>{p.name}</span>
</a>
))}
</div>
<br />
<br />
<i>Ohjelma täydentyy...</i>
</div>
{/* Laituri */}
<div className={styles.event}>
<div className={styles.programTitle}>
<span className={styles.timeSpan}>pe</span>
<span className={styles.timeSpan}>14.6.</span>
<span className={styles.timeSpan}>18 - 21</span>
</div>
<h2>
<a href='https://www.cafelaituri.fi'>
<span className={styles.placeName}>Laituri</span>
<FiExternalLink fontSize={20} />
</a>
</h2>
<div className={styles.performerList}>
{secondPerformers.map((p) => (
<a href={'/esiintyjat/' + p.id} className={styles.performerCard}>
<Image
className={styles.performerImage}
src={'/performers/2024/' + p.id + '.jpg'}
width={80}
height={80}
layout='fixed'
alt={p.name}
/>
<span className={styles.performerName}>{p.name}</span>
</a>
))}
</div>
<br />
<br />
<i>Ohjelma täydentyy...</i>
</div>
</div>
<Link href="/arkisto">
<a>
<span className={styles.archiveLinkText}>Aiempien vuosien esiintyjiä</span>
<FiExternalLink fontSize={20} />
</a>
</Link>
</section >
);
};
export default Program;

View File

@@ -1,6 +1,6 @@
import React from 'react';
import shared from '../../styles/Shared.module.scss';
import styles from '../../styles/Safety.module.scss';
import shared from '../styles/Shared.module.scss';
import styles from '../styles/Safety.module.scss';
const Safety = () => {
return (

View File

@@ -1,6 +1,6 @@
import React from 'react';
import shared from '../../styles/Shared.module.scss';
import styles from '../../styles/Workshops.module.scss';
import shared from '../styles/Shared.module.scss';
import styles from '../styles/Workshops.module.scss';
const Workshops = () => {
return (

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

View File

@@ -1,29 +0,0 @@
#!/bin/bash
set -e
APP_NAME="runosaari"
APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
echo "Deploying $APP_NAME from $APP_DIR..."
cd "$APP_DIR"
echo "Pulling latest changes..."
sudo -E git pull
echo "Installing dependencies..."
sudo bun install
echo "Building application..."
sudo bun run build
echo "Starting/reloading with pm2..."
if pm2 describe "$APP_NAME" > /dev/null 2>&1; then
pm2 reload "$APP_NAME" --update-env
else
pm2 start bun --name "$APP_NAME" -- run start
fi
pm2 save
echo "Deployment complete."

View File

@@ -1,34 +0,0 @@
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Footer from './components/Footer';
import Logo from './components/Logo';
import Index from './pages/Index';
import Performers from './pages/Performers';
import PerformerPage from './pages/PerformerPage';
import Program from './pages/Program';
import Info from './pages/Info';
import Safety from './pages/Safety';
import Workshops from './pages/Workshops';
import Archive from './pages/Archive';
function App() {
return (
<BrowserRouter>
<Logo />
<main>
<Routes>
<Route path="/" element={<Index />} />
<Route path="/performers" element={<Performers />} />
<Route path="/performers/:id" element={<PerformerPage />} />
<Route path="/program" element={<Program />} />
<Route path="/info" element={<Info />} />
<Route path="/safety" element={<Safety />} />
<Route path="/workshops" element={<Workshops />} />
<Route path="/archive" element={<Archive />} />
</Routes>
</main>
<Footer />
</BrowserRouter>
);
}
export default App;

View File

@@ -1,51 +0,0 @@
import React from 'react';
import styles from '../../styles/Collaboration.module.scss';
const Collaboration = () => {
return (
<>
<h1>Yhteistyössä</h1>
<div className={styles.collabContainer}>
<div className={styles.collabLogoRow}>
<img
className={styles.collabLogo}
src='/collaborators/skr.png'
alt='Suomen Kulttuurirahaston logo'
/>
<img
className={styles.collabLogo}
src='/collaborators/naantali.png'
alt='Naantalin kaupungin logo'
/>
<img
className={styles.collabLogo}
src='/collaborators/siltala.png'
alt='Siltalan logo'
/>
<img
className={styles.collabLogo}
src='/collaborators/teos.jpg'
alt='Teoksen logo'
/>
<img
className={styles.collabLogo}
src='/collaborators/aviador.png'
alt='Aviadorin logo'
/>
<img
className={styles.collabLogo}
src='/collaborators/vaihela.png'
alt='Vaihelan logo'
/>
<img
className={styles.collabLogo}
src='/collaborators/prosinervo.jpg'
alt='Pro Sinervon logo'
/>
</div>
</div>
</>
);
};
export default Collaboration;

View File

@@ -1,14 +0,0 @@
import React from 'react';
import styles from '../../styles/Lead.module.scss';
const Lead = () => {
return (
<div className={styles.leadContainer}>
<h2 className={styles.leadTitle}>
Kiitos tämän vuoden Runosaaresta! Tervetuloa taas ensi vuonna 3.-5.6.2027
</h2>
</div>
);
};
export default Lead;

View File

@@ -1,31 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import styles from '../../styles/Logo.module.scss';
const Logo = () => {
return (
<Link to="/">
<section className={styles.logoContainer}>
<div className={styles.logo} id='logo-start'>
<picture>
<source
srcSet='/runosaari-logo_small.jpg'
media='(max-width: 600px)'
/>
<source srcSet='/runosaari-logo.jpg' />
<img
src='/runosaari-logo.jpg'
alt='Runosaari logo'
className={styles.logoImage}
/>
</picture>
<div className={styles.logoCredits}>
<div>@Sanna Hukkanen</div>
</div>
</div>
</section>
</Link>
);
};
export default Logo;

View File

@@ -1,22 +0,0 @@
import { Link } from 'react-router-dom';
import styles from '../../styles/NavBar.module.scss';
const NavBar = () => {
return (
<>
<div className={styles.navBarContainer}>
<nav className={styles.navBar}>
<Link to='/' className={styles.navBarLink}>Etusivu</Link>
<Link to='/program' className={styles.navBarLink}>Ohjelma</Link>
<Link to='/performers' className={styles.navBarLink}>Esiintyjät</Link>
{/* <Link to='/workshops' className={styles.navBarLink}>Työpajat</Link> */}
<Link to='/info' className={styles.navBarLink}>Info</Link>
<Link to='/safety' className={styles.navBarLink}>Turvallisuus</Link>
<Link to='/archive' className={styles.navBarLink}>Arkisto</Link>
</nav>
</div>
</>
);
};
export default NavBar;

View File

@@ -1,11 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import '../styles/globals.scss';
import '../styles/transitions.scss';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

View File

@@ -1,104 +0,0 @@
import React, { useEffect, useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import shared from '../../styles/Shared.module.scss';
import styles from '../../styles/Archive.module.scss';
import PerformersData2021 from '../../data/performers/2021';
import PerformersData2022 from '../../data/performers/2022';
import PerformersData2023 from '../../data/performers/2023';
import PerformersData2024 from '../../data/performers/2024';
import PerformersData2025 from '../../data/performers/2025';
import PerformersData2026 from '../../data/performers/2026';
import Performer from '../../types/Performer';
import { BiChevronDown, BiChevronLeft } from 'react-icons/bi';
interface PerformerCard extends Performer {
showDesc: boolean;
}
const dataByYear: Record<number, Performer[]> = {
2026: PerformersData2026,
2025: PerformersData2025,
2024: PerformersData2024,
2023: PerformersData2023,
2022: PerformersData2022,
2021: PerformersData2021,
};
const sortedYears = Object.keys(dataByYear).map(Number).sort((a, b) => b - a);
const Archive = () => {
const [performersByYear, setPerformersByYear] = useState<Record<number, PerformerCard[]>>({});
useEffect(() => {
const initial: Record<number, PerformerCard[]> = {};
for (const year of sortedYears) {
initial[year] = dataByYear[year].map((p) => ({ ...p, showDesc: false }));
}
setPerformersByYear(initial);
}, []);
const togglePerformerDesc = (year: number, id: string) => {
setPerformersByYear((prev) => ({
...prev,
[year]: prev[year].map((p) =>
p.id === id ? { ...p, showDesc: !p.showDesc } : p
),
}));
};
return (
<section className={shared.page + ' ' + styles.archivePage}>
<h1>Arkisto</h1>
{sortedYears.map((year) => (
<React.Fragment key={year}>
<h2 className={styles.year}>{year}</h2>
{(performersByYear[year] ?? []).map((p) => (
<div className={styles.performerContainer} key={p.id}>
<img
className={styles.performerImage}
src={'/performers/' + year + '/' + p.id + '.jpg'}
width={100}
height={100}
loading="lazy"
alt={p.name}
/>
<div className={styles.performerTextContainer}>
<div
className={styles.performerTitle}
onClick={() => togglePerformerDesc(year, p.id)}
>
<h2>{p.name}</h2>
<button className={shared.openingChevron}>
{p.showDesc ? (
<BiChevronDown size='3rem' />
) : (
<BiChevronLeft size='3rem' />
)}
</button>
</div>
<CSSTransition
in={p.showDesc}
timeout={1000}
classNames='fadeTransition'
>
{p.showDesc ? (
<div>
{p.paragraphs.map((parag, index) => (
<p key={index}>{parag.toString()}</p>
))}
</div>
) : (
<span></span>
)}
</CSSTransition>
<hr />
</div>
</div>
))}
</React.Fragment>
))}
</section>
);
};
export default Archive;

View File

@@ -1,22 +0,0 @@
import Performers from './Performers';
import Program from './Program';
import styles from '../../styles/Index.module.scss';
import Lead from '../components/Lead';
import Collaboration from '../components/Collaboration';
const Index = () => {
return (
<div className={styles.indexContainer}>
<h1>Runosaari</h1>
<Lead />
{/* <Program /> */}
{/* <Performers /> */}
{/* <Collaboration /> */}
{/* <Workshops /> */}
{/* <Info /> */}
{/* <Archive /> */}
</div>
);
};
export default Index;

View File

@@ -1,49 +0,0 @@
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import shared from '../../styles/Shared.module.scss';
import styles from '../../styles/Performer.module.scss';
import PerformersData from '../../data/performers/2025';
import Performer from '../../types/Performer';
const PerformerPage = () => {
const { id } = useParams<{ id: string }>();
const [performer, setPerformer] = useState<Performer>({
name: '',
paragraphs: [],
id: '',
});
useEffect(() => {
setPerformer(
PerformersData.find((p) => p.id === id) ?? {
name: '',
paragraphs: [],
id: '',
}
);
}, [id]);
return performer.name === '' ? (
<div>Esiintyjää tunnisteella {id} ei löydy.</div>
) : (
<div className={styles.performerContainer}>
<img
className={styles.performerImage}
src={'/performers/2025/' + performer.id + '.jpg'}
width={300}
height={300}
loading="lazy"
alt={performer.name}
/>
<h2>{performer.name}</h2>
<div>
{performer.paragraphs.map((parag, index) => (
<p key={index}>{parag.toString()}</p>
))}
</div>
</div>
);
};
export default PerformerPage;

View File

@@ -1,116 +0,0 @@
import React from 'react';
import { FiExternalLink } from 'react-icons/fi';
import shared from '../../styles/Shared.module.scss';
import styles from '../../styles/Program.module.scss';
import { BiChevronDown, BiChevronLeft } from 'react-icons/bi';
const Program = () => {
return (
<section className={shared.page}>
<h1 id='program-start'>Ohjelma</h1>
<p className={styles.programTimeAndPlace}>
Perjantai 12.6. klo 18-21 <span className={styles.locationName}>Velkuanmaa</span>
</p>
<h2 className={styles.placeTitle}>
<a href='https://www.vaihela.fi/'>
<span className={styles.placeName}>Saaristohotelli Vaihela</span>
</a>
</h2>
<ul className={styles.performerList}>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>18.00:</span>
<span className={styles.programPerformer}>Katariina Vuorinen ja Pekka Tolonen</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>18.30:</span>
<span className={styles.programPerformer}>Outi-Illuusia Parviainen</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>19.00:</span>
<span className={styles.programPerformer}>Juha Kulmala & Jumbo!</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>20.00:</span>
<span className={styles.programPerformer}>Pegasos</span>
</li>
</ul>
<hr className={styles.programHr} />
<p className={styles.programTimeAndPlace}>
Lauantai 13.6. klo 15-21 <span className={styles.locationName}>Teersalo</span>
</p>
<h2 className={styles.placeTitle}>
<a href='https://prosinervo.com/'>
<span className={styles.placeName}>Sinervon talo</span>
</a>
</h2>
<ul className={styles.performerList}>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>15.00:</span>
<span className={styles.programPerformer}>Olli Heikkonen</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>15.20:</span>
<span className={styles.programPerformer}>Helena Sinervo</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>15.40:</span>
<span className={styles.programPerformer}>Laakso ja Siljamäki</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>16.10:</span>
<span className={styles.programPerformer}>Zoila Forss Crespo-Moreyra</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>16.30:</span>
<span className={styles.programPerformer}>Saila Susiluoto ja Markku Pääskynen</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>16.50:</span>
<span className={styles.programPerformer}>Jouni Inkala</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>17.10:</span>
<span className={styles.programPerformer}>Häivä</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>18.00:</span>
<span className={styles.programPerformer}>Olli Sinivaara</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>18.20:</span>
<span className={styles.programPerformer}>Katariina Vuorinen & Pekka Tolonen</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>18.40:</span>
<span className={styles.programPerformer}>Tommi Parkko</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>19.00:</span>
<span className={styles.programPerformer}>Djangomania (ja open mic)</span>
</li>
<li className={styles.performerWithTime}>
<span className={styles.programTime}>20.00:</span>
<span className={styles.programPerformer}>Juurakko</span>
</li>
</ul>
{/* <ul className={styles.performerList}>
<li>Santtu Puukka</li>
<li>Maaria Päivinen</li>
<li>Silja Järventausta</li>
<li>Tiina Lehikoinen</li>
<li>Katariina Vuorinen</li>
<li>Panu Hämeenaho</li>
<li>Uhrijuhla</li>
<li>Djangomania</li>
<li>Milagros Corcuera</li>
</ul> */}
<hr className={styles.programHr} />
</section>
);
};
export default Program;

View File

@@ -41,7 +41,6 @@
h2 {
margin-left: 1rem;
width: 100%;
}
h2:hover {
@@ -72,7 +71,6 @@
margin-top: 0;
}
}
.performerTextContainer {
margin-left: -0.5rem;
}

View File

@@ -12,21 +12,11 @@
}
.collabLogo {
max-width: 180px;
max-height: 100px;
width: auto;
height: auto;
object-fit: contain;
max-width: 108px;
}
.collabLogoRow {
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 3rem;
padding: 1.5rem 0;
}
@media screen and (max-width: 600px) {

View File

@@ -29,6 +29,10 @@
text-align: right;
}
.sourceLink {
margin-right: 0.5rem;
}
@media screen and (max-width: 600px) {
.container {
width: 95% !important;
@@ -36,7 +40,6 @@
align-items: center;
margin-top: 20px;
margin-bottom: 20px;
gap: 1rem;
}
.footer {
@@ -44,11 +47,7 @@
}
.middle {
order: 1;
}
.left, .right {
width: 100%;
text-align: center;
visibility: hidden;
max-height: 15px;
}
}

View File

@@ -20,7 +20,7 @@
.performerTextContainer {
width: 80%;
margin-left: 1rem;
margin-bottom: 2rem;
margin-top: 1rem;
}
.performerTitle {
@@ -32,7 +32,6 @@
h2 {
margin-left: 1rem;
width: 100%;
}
h2:hover {
@@ -42,7 +41,9 @@
}
.performerImage {
height: 100px;
border-radius: 100%;
margin-bottom: 2rem;
}
.performerButton:hover {

View File

@@ -22,7 +22,7 @@
.programTitle {
display: flex;
align-items: baseline;
justify-content: space-evenly;
justify-content: space-between;
width: 80%;
max-width: 25rem;
padding-left: 1.5rem;
@@ -39,27 +39,11 @@
}
}
.programTimeAndPlace {
width: 80%;
text-align: center;
font-size: xx-large;
}
.placeTitle {
font-size: 3.5rem !important;
.placeName {
font-size: 2.5rem;
margin-right: 1rem;
color: #2f273e;
text-decoration: none;
margin-top: 0;
a {
color: #2f273e;
text-decoration-color: #7e54e7;
}
}
.locationName {
color: #7e54e7;
}
.timeSpan {
@@ -70,16 +54,54 @@
}
.performerList {
font-size: 1.5rem;
font-weight: bold;
list-style-type: none;
line-height: 1.5rem;
max-width: 20rem;
padding-left: 0;
margin-top: 0;
display: flex;
flex-wrap: wrap;
gap: 2em;
justify-content: space-around;
margin-top: 3rem;
}
li {
margin-top: 1em;
.performerCard {
display: flex;
align-items: center;
flex-direction: column;
text-decoration: none;
color: #2f273e;
img {
border-radius: 50%;
}
}
.performerCard:hover {
color: rgb(117, 117, 117);
transition: color 0.3s;
}
.performerName {
max-width: 105px;
word-wrap: normal;
}
.eventContainer {
display: flex;
gap: 4%;
margin-bottom: 2em;
}
.event {
min-width: 40%;
padding: 4%;
background-color: #e7e2f5;
}
@media screen and (max-width: 768px) {
.eventContainer {
flex-wrap: wrap;
}
.event {
margin-top: 2em;
}
}
@@ -92,7 +114,6 @@
.programPerformer {
text-align: right;
padding-left: 1rem;
}
.programBreak {
@@ -142,3 +163,15 @@
width: 43%;
margin-top: 1em;
}
.archiveLink {
margin-top: 1rem;
}
.archiveLinkText {
font-size: 2.5rem;
margin-right: 1rem;
color: #2f273e;
text-decoration: none;
font-weight: bold;
}

View File

@@ -24,9 +24,3 @@
.followNote {
max-width: 90%;
}
.moreInfoLaterText {
margin-top: 1rem;
margin-bottom: 5rem;
font-size: 1.5rem;
}

View File

@@ -1,17 +1,20 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true
"jsx": "preserve",
"incremental": true
},
"include": ["src", "data", "types"]
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View File

@@ -1,17 +0,0 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
preview: {
port: 8089,
allowedHosts: ["runosaari.fi", "www.runosaari.fi"],
},
css: {
preprocessorOptions: {
scss: {
silenceDeprecations: ["legacy-js-api"],
},
},
},
});