diff --git a/front_end/messages/cs.json b/front_end/messages/cs.json index b890493692..5478ebe74d 100644 --- a/front_end/messages/cs.json +++ b/front_end/messages/cs.json @@ -1906,6 +1906,20 @@ "forecastsSubmitted": "Odeslaných předpovědí", "yearsOfPrediction": "let předpovědí", "featuredIn": "Zmíněno v", + "clarityInAComplexWorld": "Jasnost ve složitém světě", + "yearsOfPredictions": "{count}+ let předpovědí", + "scrollLeft": "Posunout doleva", + "scrollRight": "Posunout doprava", + "forecastingPlatform": "Prognostická platforma", + "businessSolutions": "Podniková řešení", + "collectiveIntelligenceForPublicGood": "Kolektivní inteligence pro veřejné dobro", + "forInformedDecisionMaking": "Pro informované rozhodování", + "measuringForecastingAccuracyOfAI": "Náš benchmark přesnosti AI prognóz", + "mapTheFutureBeforeYouBuildIt": "Zmapujte budoucnost, než ji postavíte", + "radiant": "Radiant", + "hire": "Najměte", + "run": "Pořádejte", + "host": "Hostujte", "popular": "Populární", "exploreAll": "Prozkoumat vše", "exploreNTournaments": "Prozkoumat {count} turnajů", @@ -1986,13 +2000,13 @@ "youHaveUnsavedProgress": "Máte neuložený postup.", "stay": "Zůstat", "stepsLeft": "{count, plural, one {# krok zbývá} few {# kroky zbývají} other {# kroků zbývá}}", - "howSoonDoYouNeedForecasts": "How soon do you need our services?", + "howSoonDoYouNeedForecasts": "Jak brzy potřebujete naše služby?", "soonerThanThreeMonths": "Dříve než za 3 měsíce", "laterThanThreeMonths": "Později než za 3 měsíce", "flexibleUnsure": "Flexibilní / zatím si nejsem jistý", "whoShouldMakeTheForecasts": "Kdo by měl dělat prognózy?", "metaculusPros": "Metaculus Pro Forecasters", - "learnAboutMetaculusPros": "What are Metaculus Pro Forecasters?", + "learnAboutMetaculusPros": "Co jsou Metaculus Pro Forecasters?", "metaculusProsDescription": "Metaculus Pro Forecasters are a vetted network of skilled forecasters with proven track records on the Metaculus platform. They specialize in making well-calibrated predictions across diverse domains.", "clientExperts": "Vaši interní odborníci", "notSure": "Nejsem si jistý", diff --git a/front_end/messages/en.json b/front_end/messages/en.json index 8c167b41a2..c9577afb58 100644 --- a/front_end/messages/en.json +++ b/front_end/messages/en.json @@ -11,6 +11,20 @@ "forecastsSubmitted": "forecasts submitted", "yearsOfPrediction": "years of predictions", "featuredIn": "Featured in", + "clarityInAComplexWorld": "Clarity in a complex world", + "yearsOfPredictions": "{count}+ years of predictions", + "scrollLeft": "Scroll left", + "scrollRight": "Scroll right", + "forecastingPlatform": "Forecasting Platform", + "businessSolutions": "Business Solutions", + "collectiveIntelligenceForPublicGood": "Collective intelligence for the public good", + "forInformedDecisionMaking": "For informed decision-making", + "measuringForecastingAccuracyOfAI": "Our AI Forecasting Benchmark", + "mapTheFutureBeforeYouBuildIt": "Map the Future Before You Build It", + "radiant": "Radiant", + "hire": "Hire", + "run": "Run", + "host": "Host", "hero1TopTitle": "Metaculus Platform", "heroIndividualsTitle": "Make decisions based on trusted community forecasts", "exploreQuestions": "Explore questions", diff --git a/front_end/messages/es.json b/front_end/messages/es.json index 781d7c3a65..48acf4a43c 100644 --- a/front_end/messages/es.json +++ b/front_end/messages/es.json @@ -1901,6 +1901,20 @@ "forecastsSubmitted": "Pronósticos enviados", "yearsOfPrediction": "Años de predicción", "featuredIn": "Destacado en", + "clarityInAComplexWorld": "Claridad en un mundo complejo", + "yearsOfPredictions": "{count}+ años de predicciones", + "scrollLeft": "Desplazar a la izquierda", + "scrollRight": "Desplazar a la derecha", + "forecastingPlatform": "Plataforma de Pronósticos", + "businessSolutions": "Soluciones Empresariales", + "collectiveIntelligenceForPublicGood": "Inteligencia colectiva para el bien público", + "forInformedDecisionMaking": "Para la toma de decisiones informadas", + "measuringForecastingAccuracyOfAI": "Nuestro benchmark de predicción con IA", + "mapTheFutureBeforeYouBuildIt": "Mapea el futuro antes de construirlo", + "radiant": "Radiant", + "hire": "Contrata", + "run": "Ejecuta", + "host": "Aloja", "popular": "Popular", "exploreAll": "Explorar todo", "exploreNTournaments": "Explorar {count} torneos", @@ -1986,13 +2000,13 @@ "youHaveUnsavedProgress": "Tienes progreso sin guardar.", "stay": "Quedarse", "stepsLeft": "{count, plural, one {# paso restante} other {# pasos restantes}}", - "howSoonDoYouNeedForecasts": "How soon do you need our services?", + "howSoonDoYouNeedForecasts": "¿Qué tan pronto necesita nuestros servicios?", "soonerThanThreeMonths": "Antes de 3 meses", "laterThanThreeMonths": "Después de 3 meses", "flexibleUnsure": "Flexible / aún no estoy seguro", "whoShouldMakeTheForecasts": "¿Quién debería hacer las previsiones?", "metaculusPros": "Metaculus Pro Forecasters", - "learnAboutMetaculusPros": "What are Metaculus Pro Forecasters?", + "learnAboutMetaculusPros": "¿Qué son los Metaculus Pro Forecasters?", "metaculusProsDescription": "Metaculus Pro Forecasters are a vetted network of skilled forecasters with proven track records on the Metaculus platform. They specialize in making well-calibrated predictions across diverse domains.", "clientExperts": "Tus expertos internos", "notSure": "No estoy seguro", diff --git a/front_end/messages/pt.json b/front_end/messages/pt.json index 7d46728750..75bd199fe6 100644 --- a/front_end/messages/pt.json +++ b/front_end/messages/pt.json @@ -1899,6 +1899,20 @@ "forecastsSubmitted": "Previsões enviadas", "yearsOfPrediction": "anos de previsões", "featuredIn": "Destaque em", + "clarityInAComplexWorld": "Clareza em um mundo complexo", + "yearsOfPredictions": "{count}+ anos de previsões", + "scrollLeft": "Rolar para a esquerda", + "scrollRight": "Rolar para a direita", + "forecastingPlatform": "Plataforma de Previsão", + "businessSolutions": "Soluções Empresariais", + "collectiveIntelligenceForPublicGood": "Inteligência coletiva para o bem público", + "forInformedDecisionMaking": "Para tomada de decisões informadas", + "measuringForecastingAccuracyOfAI": "Nosso benchmark de previsão com IA", + "mapTheFutureBeforeYouBuildIt": "Mapeie o futuro antes de construí-lo", + "radiant": "Radiant", + "hire": "Contrate", + "run": "Execute", + "host": "Hospede", "popular": "Popular", "exploreAll": "Explorar tudo", "exploreNTournaments": "Explore {count} torneios", @@ -1984,13 +1998,13 @@ "youHaveUnsavedProgress": "Você tem progresso não salvo.", "stay": "Ficar", "stepsLeft": "{count, plural, one {# passo restante} other {# passos restantes}}", - "howSoonDoYouNeedForecasts": "How soon do you need our services?", + "howSoonDoYouNeedForecasts": "Quando você precisa dos nossos serviços?", "soonerThanThreeMonths": "Mais rápido que 3 meses", "laterThanThreeMonths": "Mais tarde que 3 meses", "flexibleUnsure": "Flexível / ainda não tenho certeza", "whoShouldMakeTheForecasts": "Quem deve fazer as previsões?", "metaculusPros": "Metaculus Pro Forecasters", - "learnAboutMetaculusPros": "What are Metaculus Pro Forecasters?", + "learnAboutMetaculusPros": "O que são os Metaculus Pro Forecasters?", "metaculusProsDescription": "Metaculus Pro Forecasters are a vetted network of skilled forecasters with proven track records on the Metaculus platform. They specialize in making well-calibrated predictions across diverse domains.", "clientExperts": "Seus especialistas internos", "notSure": "Não tenho certeza", diff --git a/front_end/messages/zh-TW.json b/front_end/messages/zh-TW.json index 2132a14e32..68a98ba5db 100644 --- a/front_end/messages/zh-TW.json +++ b/front_end/messages/zh-TW.json @@ -1895,6 +1895,20 @@ "forecastsSubmitted": "已提交預測", "yearsOfPrediction": "預測年數", "featuredIn": "媒體報導", + "clarityInAComplexWorld": "在複雜世界中看清未來", + "yearsOfPredictions": "{count}+ 年預測", + "scrollLeft": "向左滾動", + "scrollRight": "向右滾動", + "forecastingPlatform": "預測平台", + "businessSolutions": "商業解決方案", + "collectiveIntelligenceForPublicGood": "為公共利益服務的集體智慧", + "forInformedDecisionMaking": "為明智決策服務", + "measuringForecastingAccuracyOfAI": "我們的AI預測準確度基準", + "mapTheFutureBeforeYouBuildIt": "在構建之前繪製未來藍圖", + "radiant": "Radiant", + "hire": "僱用", + "run": "舉辦", + "host": "託管", "popular": "熱門", "exploreAll": "探索全部", "exploreNTournaments": "探索 {count} 場比賽", @@ -1983,13 +1997,13 @@ "youHaveUnsavedProgress": "您有未儲存的進度。", "stay": "留下", "stepsLeft": "{count, plural, one {還剩 # 步} other {還剩 # 步}}", - "howSoonDoYouNeedForecasts": "How soon do you need our services?", + "howSoonDoYouNeedForecasts": "您多快需要我們的服務?", "soonerThanThreeMonths": "少於 3 個月", "laterThanThreeMonths": "多於 3 個月", "flexibleUnsure": "靈活 / 尚不確定", "whoShouldMakeTheForecasts": "誰應該製作預測?", "metaculusPros": "Metaculus Pro Forecasters", - "learnAboutMetaculusPros": "What are Metaculus Pro Forecasters?", + "learnAboutMetaculusPros": "什麼是 Metaculus Pro Forecasters?", "metaculusProsDescription": "Metaculus Pro Forecasters are a vetted network of skilled forecasters with proven track records on the Metaculus platform. They specialize in making well-calibrated predictions across diverse domains.", "clientExperts": "您的內部專家", "notSure": "不確定", diff --git a/front_end/messages/zh.json b/front_end/messages/zh.json index cd2c8290fe..e1dde04499 100644 --- a/front_end/messages/zh.json +++ b/front_end/messages/zh.json @@ -1903,6 +1903,20 @@ "forecastsSubmitted": "已提交预测", "yearsOfPrediction": "预测年数", "featuredIn": "媒体报道", + "clarityInAComplexWorld": "在复杂世界中看清未来", + "yearsOfPredictions": "{count}+ 年预测", + "scrollLeft": "向左滚动", + "scrollRight": "向右滚动", + "forecastingPlatform": "预测平台", + "businessSolutions": "商业解决方案", + "collectiveIntelligenceForPublicGood": "为公共利益服务的集体智慧", + "forInformedDecisionMaking": "为明智决策服务", + "measuringForecastingAccuracyOfAI": "我们的AI预测准确度基准", + "mapTheFutureBeforeYouBuildIt": "在构建之前绘制未来蓝图", + "radiant": "Radiant", + "hire": "雇用", + "run": "举办", + "host": "托管", "popular": "热门", "exploreAll": "探索全部", "exploreNTournaments": "探索 {count} 个锦标赛", @@ -1988,13 +2002,13 @@ "youHaveUnsavedProgress": "您有未保存的进度。", "stay": "停留", "stepsLeft": "{count, plural, one {剩下 # 步} other {剩下 # 步}}", - "howSoonDoYouNeedForecasts": "How soon do you need our services?", + "howSoonDoYouNeedForecasts": "您多快需要我们的服务?", "soonerThanThreeMonths": "少于 3 个月", "laterThanThreeMonths": "超过 3 个月", "flexibleUnsure": "灵活 / 尚不确定", "whoShouldMakeTheForecasts": "谁应该进行预测?", "metaculusPros": "Metaculus Pro Forecasters", - "learnAboutMetaculusPros": "What are Metaculus Pro Forecasters?", + "learnAboutMetaculusPros": "什么是 Metaculus Pro Forecasters?", "metaculusProsDescription": "Metaculus Pro Forecasters are a vetted network of skilled forecasters with proven track records on the Metaculus platform. They specialize in making well-calibrated predictions across diverse domains.", "clientExperts": "您的内部专家", "notSure": "不确定", diff --git a/front_end/package-lock.json b/front_end/package-lock.json index 2503f35510..3cdf7948bc 100644 --- a/front_end/package-lock.json +++ b/front_end/package-lock.json @@ -25,6 +25,8 @@ "@marsidev/react-turnstile": "^0.7.2", "@mdxeditor/editor": "^3.23.2", "@next/third-parties": "15.2.4", + "@paper-design/shaders": "^0.0.72", + "@paper-design/shaders-react": "^0.0.72", "@sentry/nextjs": "^9.47.1", "@storybook/addon-themes": "^9.0.14", "@storybook/nextjs-vite": "^9.0.13", @@ -175,6 +177,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -2266,6 +2269,7 @@ "version": "6.10.2", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.2.tgz", "integrity": "sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==", + "peer": true, "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -2347,12 +2351,14 @@ "node_modules/@codemirror/state": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", - "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==", + "peer": true }, "node_modules/@codemirror/view": { "version": "6.28.1", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.1.tgz", "integrity": "sha512-BUWr+zCJpMkA/u69HlJmR+YkV4yPpM81HeMkOMZuwFa8iM5uJdEPKAs1icIRZKkKmy0Ub1x9/G3PQLTXdpBxrQ==", + "peer": true, "dependencies": { "@codemirror/state": "^6.4.0", "style-mod": "^4.1.0", @@ -3042,6 +3048,7 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", "hasInstallScript": true, + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "6.5.2" }, @@ -4333,7 +4340,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -4610,6 +4616,7 @@ "version": "0.23.1", "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.23.1.tgz", "integrity": "sha512-yXEkF6fj32+mJblCoP0ZT/vA0S05FA0nRUkVrvGX6sbZ9y+cIzuIbBoHi4z1ytutcWHQrwCK4TsN9hPYBIlb2w==", + "peer": true, "dependencies": { "@lexical/list": "0.23.1", "@lexical/selection": "0.23.1", @@ -4669,6 +4676,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", + "peer": true, "dependencies": { "@lezer/common": "^1.0.0" } @@ -5120,6 +5128,7 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -5154,6 +5163,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.0.tgz", "integrity": "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -5212,6 +5222,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.57.2.tgz", "integrity": "sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/api-logs": "0.57.2", "@types/shimmer": "^1.2.0", @@ -5953,6 +5964,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.0.tgz", "integrity": "sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/semantic-conventions": "^1.29.0" @@ -6087,6 +6099,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=14" } @@ -6130,6 +6143,30 @@ "node": ">=14" } }, + "node_modules/@paper-design/shaders": { + "version": "0.0.72", + "resolved": "https://registry.npmjs.org/@paper-design/shaders/-/shaders-0.0.72.tgz", + "integrity": "sha512-rk2BFuV5ood2DaivbxJC2jQMzaB434isDUzdUQ85Cy0OWnUMuxl8kyGMR74TDPyjo3EvcHIyreNLkJdRG+GfSA==", + "license": "SEE LICENSE IN https://github.com/paper-design/shaders/blob/main/LICENSE" + }, + "node_modules/@paper-design/shaders-react": { + "version": "0.0.72", + "resolved": "https://registry.npmjs.org/@paper-design/shaders-react/-/shaders-react-0.0.72.tgz", + "integrity": "sha512-q6KwquL93ZVNcuSM7pqzW0z/VLjnDVb/NSpYyGJBxf7MEHHCXx37E+zw/Px6RZLt3SGCUerIDDCGCMT385oW0w==", + "license": "SEE LICENSE IN https://github.com/paper-design/shaders/blob/main/LICENSE", + "dependencies": { + "@paper-design/shaders": "0.0.72" + }, + "peerDependencies": { + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -7155,6 +7192,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8732,6 +8770,7 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -8971,6 +9010,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz", "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/query-core": "5.90.20" }, @@ -9060,6 +9100,7 @@ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -9536,7 +9577,6 @@ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -9547,7 +9587,6 @@ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -9674,8 +9713,7 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -9731,6 +9769,7 @@ "version": "20.17.19", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz", "integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==", + "peer": true, "dependencies": { "undici-types": "~6.19.2" } @@ -9786,6 +9825,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz", "integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -9794,6 +9834,7 @@ "version": "19.0.4", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz", "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==", + "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -9940,6 +9981,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz", "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.15.0", "@typescript-eslint/types": "8.15.0", @@ -10243,7 +10285,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" @@ -10253,29 +10294,25 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", @@ -10286,15 +10323,13 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -10307,7 +10342,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "license": "MIT", - "peer": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -10317,7 +10351,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -10326,15 +10359,13 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -10351,7 +10382,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", @@ -10365,7 +10395,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -10378,7 +10407,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", @@ -10393,7 +10421,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" @@ -10403,15 +10430,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/abab": { "version": "2.0.6", @@ -10437,6 +10462,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -10468,7 +10494,6 @@ "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.13.0" }, @@ -10539,7 +10564,6 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "license": "MIT", - "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -10557,7 +10581,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -10573,8 +10596,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/anser": { "version": "2.3.2", @@ -11278,6 +11300,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -11573,7 +11596,6 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.0" } @@ -12138,7 +12160,8 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "peer": true }, "node_modules/d": { "version": "1.0.2", @@ -12444,6 +12467,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "peer": true, "engines": { "node": ">=12" } @@ -12645,6 +12669,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" @@ -12862,7 +12887,8 @@ "version": "0.0.1312386", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/didyoumean": { "version": "1.2.2", @@ -13097,7 +13123,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/embla-carousel-auto-scroll": { "version": "8.6.0", @@ -13308,8 +13335,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.0.0", @@ -13405,6 +13431,7 @@ "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -13501,6 +13528,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -13584,6 +13612,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -13667,6 +13696,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -14051,7 +14081,6 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.8.x" } @@ -14220,8 +14249,7 @@ "url": "https://opencollective.com/fastify" } ], - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/fastq": { "version": "1.17.1", @@ -14698,8 +14726,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause", - "peer": true + "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/balanced-match": { "version": "4.0.4", @@ -15856,7 +15883,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", - "peer": true, "funding": { "type": "GitHub Sponsors ❤", "url": "https://github.com/sponsors/dmonad" @@ -17066,7 +17092,6 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -17081,7 +17106,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -17097,6 +17121,7 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -17448,7 +17473,8 @@ "node_modules/lexical": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.23.1.tgz", - "integrity": "sha512-iuS72HcAYUemsCRQCm4XZzkGhZb8a9KagW+ee2TFfkkf9f3ZpUYSrobMpjYVZRkgMOx7Zk5VCPMxm1nouJTfnQ==" + "integrity": "sha512-iuS72HcAYUemsCRQCm4XZzkGhZb8a9KagW+ee2TFfkkf9f3ZpUYSrobMpjYVZRkgMOx7Zk5VCPMxm1nouJTfnQ==", + "peer": true }, "node_modules/lexical-beautiful-mentions": { "version": "0.1.44", @@ -17466,7 +17492,6 @@ "version": "0.2.99", "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.99.tgz", "integrity": "sha512-vwztYuUf1uf/1zQxfzRfO5yzfNKhTtgOByCruuiQQxWQXnPb8Itaube5ylofcV0oM0aKal9Mv+S1s1Ky0UYP1w==", - "peer": true, "dependencies": { "isomorphic.js": "^0.2.4" }, @@ -17694,7 +17719,6 @@ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.11.5" }, @@ -19082,8 +19106,7 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/netmask": { "version": "2.0.2", @@ -19099,6 +19122,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-15.5.12.tgz", "integrity": "sha512-Fi/wQ4Etlrn60rz78bebG1i1SR20QxvV8tVp6iJspjLUSHcZoeUXCt+vmWoEcza85ElZzExK/jJ/F6SvtGktjA==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "15.5.12", "@swc/helpers": "0.5.15", @@ -20622,6 +20646,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -20846,6 +20871,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz", "integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==", "devOptional": true, + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -21289,6 +21315,7 @@ "version": "19.0.0", "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -21314,6 +21341,7 @@ "version": "19.0.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "peer": true, "dependencies": { "scheduler": "^0.25.0" }, @@ -21341,6 +21369,7 @@ "version": "7.52.1", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.1.tgz", "integrity": "sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg==", + "peer": true, "engines": { "node": ">=12.22.0" }, @@ -21756,7 +21785,6 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -21989,6 +22017,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -22189,6 +22218,7 @@ "version": "1.77.6", "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", + "peer": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -22232,7 +22262,6 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "license": "MIT", - "peer": true, "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -22269,7 +22298,6 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -22281,8 +22309,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/semver": { "version": "7.7.3", @@ -22633,7 +22660,6 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -22733,6 +22759,7 @@ "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.19.tgz", "integrity": "sha512-P7K/b+Pn1sXJzwYCF6hH5Zjdrg4ZlA5Bz9rdOJEdvm6ev27XESDGI+Ql+dfUfUcGOym3Aud4MssJIDEF2ocsyQ==", "license": "MIT", + "peer": true, "dependencies": { "@storybook/global": "^5.0.0", "@testing-library/jest-dom": "^6.6.3", @@ -23319,6 +23346,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "license": "MIT", + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -23449,7 +23477,6 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -23468,7 +23495,6 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", @@ -23501,8 +23527,7 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/test-exclude": { "version": "6.0.0", @@ -23595,7 +23620,6 @@ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "license": "MIT", - "peer": true, "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" @@ -23612,7 +23636,6 @@ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "license": "MIT", - "peer": true, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -23741,6 +23764,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -23947,6 +23971,7 @@ "version": "5.8.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -24939,7 +24964,6 @@ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "license": "MIT", - "peer": true, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -25012,7 +25036,6 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "license": "MIT", - "peer": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -25045,7 +25068,6 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -25109,7 +25131,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -25123,7 +25144,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=4.0" } @@ -25461,6 +25481,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -25570,6 +25591,7 @@ "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/front_end/package.json b/front_end/package.json index 247bb9678e..0fa1a7fbe2 100644 --- a/front_end/package.json +++ b/front_end/package.json @@ -35,6 +35,8 @@ "@marsidev/react-turnstile": "^0.7.2", "@mdxeditor/editor": "^3.23.2", "@next/third-parties": "15.2.4", + "@paper-design/shaders": "^0.0.72", + "@paper-design/shaders-react": "^0.0.72", "@sentry/nextjs": "^9.47.1", "@storybook/addon-themes": "^9.0.14", "@storybook/nextjs-vite": "^9.0.13", diff --git a/front_end/src/app/(main)/(home)/components/all_categories_section.tsx b/front_end/src/app/(main)/(home)/components/all_categories_section.tsx deleted file mode 100644 index 0398ab9b24..0000000000 --- a/front_end/src/app/(main)/(home)/components/all_categories_section.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import Link from "next/link"; -import { getTranslations } from "next-intl/server"; -import { FC } from "react"; - -import { - POST_CATEGORIES_FILTER, - POST_FOR_MAIN_FEED, -} from "@/constants/posts_feed"; -import { Post } from "@/types/post"; -import { Category } from "@/types/projects"; -import cn from "@/utils/core/cn"; - -type CategoryWithPosts = Category & { posts: Post[] }; - -type Props = { - categories: CategoryWithPosts[]; - className?: string; -}; - -const AllCategoriesSection: FC = async ({ categories, className }) => { - const t = await getTranslations(); - - if (!categories || categories.length === 0) { - return null; - } - - const sortedCategories = [...categories] - .filter((c) => c && c.name) - .sort((a, b) => a.name.localeCompare(b.name)); - - return ( -
-

- - {t("allCategoriesTopQuestions")} - - - {t("allCategories")} -

-
- {sortedCategories.map((category) => ( - - ))} -
-
- ); -}; - -type CategoryCardProps = { - category: CategoryWithPosts; -}; - -const CategoryCard: FC = ({ category }) => { - const categoryUrl = `/questions/?${POST_CATEGORIES_FILTER}=${category.slug}&${POST_FOR_MAIN_FEED}=false`; - - return ( -
- - {category.emoji} - - {category.name} - - - - {category.posts && category.posts.length > 0 && ( -
- {category.posts.slice(0, 3).map(({ title, slug, id }, index) => ( -
-
- - {index + 1}. - - - {title} - -
- {index < Math.min(category.posts.length, 3) - 1 && ( -
- )} -
- ))} -
- )} -
- ); -}; - -export default AllCategoriesSection; diff --git a/front_end/src/app/(main)/(home)/components/featured_in_marquee.tsx b/front_end/src/app/(main)/(home)/components/featured_in_marquee.tsx new file mode 100644 index 0000000000..138190ff09 --- /dev/null +++ b/front_end/src/app/(main)/(home)/components/featured_in_marquee.tsx @@ -0,0 +1,131 @@ +"use client"; + +import AutoScroll from "embla-carousel-auto-scroll"; +import useEmblaCarousel from "embla-carousel-react"; +import { useTranslations } from "next-intl"; +import { FC, ReactNode } from "react"; + +import cn from "@/utils/core/cn"; + +import { + NasdaqLogo, + ForbesLogo, + TheAtlanticLogo, + AeiLogo, + TheEconomistLogo, + BloombergLogo, +} from "./featured-in-logos"; + +type FeaturedItem = { + href: string; + label: string; + articleTitle: string; + component: ReactNode; +}; + +const FEATURED_IN: FeaturedItem[] = [ + { + href: "https://www.nasdaq.com/articles/how-crypto-can-help-secure-ai", + label: "Nasdaq", + articleTitle: "How Crypto Can Help Secure AI", + component: , + }, + { + href: "https://www.forbes.com/sites/stevenwolfepereira/2025/12/08/building-a-one-person-unicorn-this-startup-just-raised-87m-to-help/", + label: "Forbes", + articleTitle: + "Building A One-Person Unicorn: This Startup Just Raised $87M To Help", + component: , + }, + { + href: "https://archive.is/0O588", + label: "The Atlantic", + articleTitle: "The Atlantic Feature", + component: , + }, + { + href: "https://www.aei.org/articles/the-great-ai-forecasting-divide/1", + label: "AEI", + articleTitle: "The Great AI Forecasting Divide", + component: , + }, + { + href: "https://www.economist.com/finance-and-economics/2023/05/23/what-would-humans-do-in-a-world-of-super-ai", + label: "The Economist", + articleTitle: "What Would Humans Do in a World of Super AI?", + component: , + }, + { + href: "https://www.bloomberg.com/opinion/articles/2024-03-24/can-sam-altman-make-ai-smart-enough-to-answer-these-6-questions", + label: "Bloomberg", + articleTitle: + "Can Sam Altman Make AI Smart Enough to Answer These 6 Questions?", + component: , + }, +]; + +const FeaturedInMarquee: FC<{ className?: string }> = ({ className }) => { + const t = useTranslations(); + + const [emblaRef] = useEmblaCarousel( + { + loop: true, + align: "start", + containScroll: "trimSnaps", + watchDrag: false, + }, + [ + AutoScroll({ + speed: 0.3, + stopOnInteraction: false, + stopOnMouseEnter: true, + }), + ] + ); + + // Duplicate for seamless infinite scrolling + const logos = [...FEATURED_IN, ...FEATURED_IN, ...FEATURED_IN]; + + return ( +
+ + {t("featuredIn")} + + +
+
+
+ {logos.map((item, index) => { + const isClone = index >= FEATURED_IN.length; + return ( + + ); + })} +
+
+
+
+
+
+ ); +}; + +export default FeaturedInMarquee; diff --git a/front_end/src/app/(main)/(home)/components/force_light_mode.tsx b/front_end/src/app/(main)/(home)/components/force_light_mode.tsx new file mode 100644 index 0000000000..1cc65162da --- /dev/null +++ b/front_end/src/app/(main)/(home)/components/force_light_mode.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { useLayoutEffect } from "react"; + +export default function ForceLightMode() { + useLayoutEffect(() => { + const html = document.documentElement; + + // Remove dark class immediately + html.classList.remove("dark"); + + // Prevent next-themes (or anything else) from re-adding it + const observer = new MutationObserver(() => { + if (html.classList.contains("dark")) { + html.classList.remove("dark"); + } + }); + + observer.observe(html, { + attributes: true, + attributeFilter: ["class"], + }); + + return () => { + observer.disconnect(); + // Restore dark mode if the user's saved preference requires it + const saved = localStorage.getItem("theme"); + if ( + saved === "dark" || + (!saved && window.matchMedia("(prefers-color-scheme: dark)").matches) || + (saved === "system" && + window.matchMedia("(prefers-color-scheme: dark)").matches) + ) { + html.classList.add("dark"); + } + }; + }, []); + + return null; +} diff --git a/front_end/src/app/(main)/(home)/components/forecasts_carousel_section.tsx b/front_end/src/app/(main)/(home)/components/forecasts_carousel_section.tsx new file mode 100644 index 0000000000..45b60c190e --- /dev/null +++ b/front_end/src/app/(main)/(home)/components/forecasts_carousel_section.tsx @@ -0,0 +1,114 @@ +"use client"; + +import { faArrowLeft, faArrowRight } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useTranslations } from "next-intl"; +import { FC, useCallback, useEffect, useRef, useState } from "react"; + +import { PostWithForecasts } from "@/types/post"; +import cn from "@/utils/core/cn"; +import { isConditionalPost, isNotebookPost } from "@/utils/questions/helpers"; + +import HomepagePostCard from "./homepage_post_card"; + +type Props = { + initialPosts: PostWithForecasts[]; + className?: string; +}; + +const CARD_WIDTH_MOBILE = 220; +const CARD_GAP = 16; + +const ForecastsCarouselSection: FC = ({ initialPosts, className }) => { + const t = useTranslations(); + const posts = initialPosts.filter( + (post) => !isConditionalPost(post) && !isNotebookPost(post) + ); + + const scrollRef = useRef(null); + const [canScrollLeft, setCanScrollLeft] = useState(false); + const [canScrollRight, setCanScrollRight] = useState(true); + + const updateScrollState = useCallback(() => { + const el = scrollRef.current; + if (!el) return; + setCanScrollLeft(el.scrollLeft > 1); + setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1); + }, []); + + useEffect(() => { + const el = scrollRef.current; + if (!el) return; + updateScrollState(); + el.addEventListener("scroll", updateScrollState, { passive: true }); + const observer = new ResizeObserver(updateScrollState); + observer.observe(el); + return () => { + el.removeEventListener("scroll", updateScrollState); + observer.disconnect(); + }; + }, [updateScrollState]); + + const scroll = useCallback((direction: 1 | -1) => { + const el = scrollRef.current; + if (!el) return; + + const isMobile = window.innerWidth < 768; + const amount = isMobile + ? CARD_WIDTH_MOBILE + CARD_GAP + : el.clientWidth * 0.33; + + el.scrollBy({ left: direction * amount, behavior: "smooth" }); + }, []); + + return ( +
+
+ {posts.map((post) => ( +
+ +
+ ))} +
+ +
+ + +
+ ); +}; + +export default ForecastsCarouselSection; diff --git a/front_end/src/app/(main)/(home)/components/future_eval_section.tsx b/front_end/src/app/(main)/(home)/components/future_eval_section.tsx deleted file mode 100644 index be8394c2b0..0000000000 --- a/front_end/src/app/(main)/(home)/components/future_eval_section.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import Link from "next/link"; -import { getTranslations } from "next-intl/server"; -import { FC } from "react"; - -import WithServerComponentErrorBoundary from "@/components/server_component_error_boundary"; -import Button from "@/components/ui/button"; -import ServerLeaderboardApi from "@/services/api/leaderboard/leaderboard.server"; -import cn from "@/utils/core/cn"; - -import FutureEvalTable from "./future_eval_table"; - -const ListStarIcon = () => ( - - - - - - - - - - - - - - - -); - -const PersonIcon = () => ( - - - - - - - - - - - -); - -const TrophyIcon = () => ( - - - - - - - - - - -); - -type FeatureItemProps = { - icon: React.ReactNode; - title: string; - description: React.ReactNode; -}; - -const FeatureItem: FC = ({ icon, title, description }) => ( -
-
- {icon} -
-
-

- {title} -

-

- {description} -

-
-
-); - -const FutureEvalSection: FC<{ className?: string }> = async ({ className }) => { - const t = await getTranslations(); - const data = await ServerLeaderboardApi.getGlobalLeaderboard( - null, - null, - "manual", - "Global Bot Leaderboard" - ); - - const hasData = data?.entries?.length > 0; - if (!hasData) { - return null; - } - - return ( -
- {/* Header */} -
-
-

- {t("metaculusFutureEval")} -

-

- {t("futureEvalDescription")} -

-
- -
- - {/* Content */} -
- {/* Info box - determines container height */} -
-
-

- {t("futureEvalTagline")} -

-
- } - title={t("modelLeaderboard")} - description={t("modelLeaderboardDescription")} - /> - } - title={t("botsVsHumans")} - description={t("botsVsHumansDescription")} - /> - } - title={t("startCompeting")} - description={ - <> - {t("startCompetingDescription")}{" "} - - {t("miniBench")} - - . - - } - /> -
-
-
- - {/* Table wrapper - stretches to match first child height, content scrolls */} -
- -
-
-
- ); -}; - -export default WithServerComponentErrorBoundary(FutureEvalSection); diff --git a/front_end/src/app/(main)/(home)/components/future_eval_table.tsx b/front_end/src/app/(main)/(home)/components/future_eval_table.tsx deleted file mode 100644 index 7f824313d7..0000000000 --- a/front_end/src/app/(main)/(home)/components/future_eval_table.tsx +++ /dev/null @@ -1,170 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { useTranslations } from "next-intl"; -import { FC, useMemo } from "react"; - -import { - entryIconPair, - entryLabel, - shouldDisplayEntry, -} from "@/app/(futureeval)/futureeval/components/leaderboard/utils"; -import MedalIcon from "@/app/(main)/(leaderboards)/components/medal_icon"; -import { LightDarkIcon } from "@/components/ui/light-dark-icon"; -import type { LeaderboardDetails, MedalType } from "@/types/scoring"; -import cn from "@/utils/core/cn"; - -type Props = { details: LeaderboardDetails; className?: string }; - -const INITIAL_ROWS = 8; - -const MEDALS: Record = { - 1: "gold", - 2: "silver", - 3: "bronze", -}; - -const MedalRow: FC<{ rank: number }> = ({ rank }) => { - const medalType = MEDALS[rank]; - - return medalType ? ( - - ) : ( - - {rank} - - ); -}; - -const FutureEvalTable: React.FC = ({ details, className }) => { - const t = useTranslations(); - - const rows = useMemo(() => { - const entries = (details.entries ?? []) - .filter((e) => shouldDisplayEntry(e)) - .map((entry, i) => { - const label = entryLabel(entry); - const icons = entryIconPair(entry); - const userId = entry.user?.id; - return { - rank: i + 1, - label, - username: entry.user?.username ?? "", - icons, - forecasts: entry.contribution_count, - score: entry.score, - profileHref: userId ? `/accounts/profile/${userId}/` : null, - isAggregate: !entry.user?.username, - }; - }); - - return entries; - }, [details.entries]); - - const visibleRows = rows.slice(0, INITIAL_ROWS); - - return ( -
-
- - - - - - - - - - - - - - - - - {visibleRows.map((r) => ( - - - - - - - - - ))} - -
{t("rank")}{t("aibLbThModel")}{t("score")} - {t("aibLbThForecasts")} -
-
- -
-
-
- {(r.icons.light || r.icons.dark) && ( - - )} -
- {r.isAggregate || !r.profileHref ? ( - r.label - ) : ( - - {r.label} - - )} -
-
-
- - {fmt(r.score, 2)} - - - - {r.forecasts} - -
-
- {rows.length > INITIAL_ROWS && ( - - {t("viewMore")} - - )} -
- ); -}; - -const fmt = (n: number | null | undefined, d = 2) => - n == null || Number.isNaN(n) ? "—" : n.toFixed(d); - -const Th: React.FC> = ({ - className = "", - children, -}) => ( - - {children} - -); - -const Td: React.FC> = ({ - className = "", - children, -}) => {children}; - -export default FutureEvalTable; diff --git a/front_end/src/app/(main)/(home)/components/hero_ctas.tsx b/front_end/src/app/(main)/(home)/components/hero_ctas.tsx deleted file mode 100644 index e69f5ea57f..0000000000 --- a/front_end/src/app/(main)/(home)/components/hero_ctas.tsx +++ /dev/null @@ -1,270 +0,0 @@ -"use client"; - -import { faArrowRight } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import useEmblaCarousel from "embla-carousel-react"; -import Link from "next/link"; -import { useTranslations } from "next-intl"; -import { FC, PropsWithChildren, ReactNode } from "react"; - -import FutureEvalSymbol from "@/app/(futureeval)/futureeval/components/futureeval-symbol"; -import { FE_COLORS } from "@/app/(futureeval)/futureeval/theme"; -import { useBreakpoint } from "@/hooks/tailwind"; -import cn from "@/utils/core/cn"; - -type HeroCTACardVariant = "blue" | "purple" | "futureEval"; - -const variantStyles: Record< - HeroCTACardVariant, - { bg: string; text: string; textLight: string; hover: string } -> = { - blue: { - bg: "bg-blue-300 dark:bg-blue-300-dark", - text: "text-blue-800 dark:text-blue-800-dark", - textLight: "text-blue-700 dark:text-blue-700-dark", - hover: "hover:bg-blue-400/80 dark:hover:bg-blue-400-dark/70", - }, - purple: { - bg: "bg-purple-100 dark:bg-purple-200-dark/70", - text: "text-purple-800 dark:text-purple-800-dark", - textLight: "text-purple-700 dark:text-purple-700-dark", - hover: "hover:bg-purple-300/60 dark:hover:bg-purple-300-dark/60", - }, - futureEval: { - bg: "bg-[#469C93]/15 dark:bg-[#23FBE3]/15", - text: "text-[#474747] dark:text-[#EDF7F3]", - textLight: FE_COLORS.textAccent, - hover: "hover:bg-[#469C93]/20 dark:hover:bg-[#23FBE3]/20", - }, -}; - -type HeroCTACardProps = { - href: string; - topTitle: ReactNode; - subtitle: string; - variant: HeroCTACardVariant; - topTitleClassName?: string; - arrowClassName?: string; -}; - -const HeroCTACard: FC> = ({ - href, - topTitle, - subtitle, - children, - variant, - topTitleClassName, - arrowClassName, -}) => { - const { - bg: bgColorClasses, - text: textColorClasses, - textLight: textLightClasses, - hover: hoverClasses, - } = variantStyles[variant]; - - return ( - -
-
- {topTitle} -
- -
-
-

- {subtitle} -

-
{children}
-
- - ); -}; - -type Props = { - platformHref?: string; - servicesHref?: string; - futureEvalHref?: string; - className?: string; -}; - -const HeroCTAs: FC = ({ - platformHref = "/questions/", - servicesHref = "/services/", - futureEvalHref = "/futureeval/", - className, -}) => { - const t = useTranslations(); - const isMdScreen = useBreakpoint("md"); - const [emblaRef] = useEmblaCarousel({ - align: "start", - containScroll: "trimSnaps", - watchDrag: !isMdScreen, - }); - - return ( -
-
-
-
- -
-
-

- {t("followImportantTopics")} -

-

- {t("followImportantTopicsDescription")} -

-
-
-

- {t("practiceForecasting")} -

-

- {t("practiceForecastingDescription")} -

-
- {/** NOTE: removed when added future eval card -
-

- {t("cashPrizesForAccuracy")} -

-

- {t("cashPrizesForAccuracyDescription")} -

-
- */} -
-
-
- -
- -
-
-

- {t("hireProForecasters")} -

-

- {t("hireProForecastersDescription")} -

-
-
-

- {t("launchTournament")} -

-

- {t("launchTournamentDescription")} -

-
- {/** NOTE: removed when added future eval card -
-

- {t("hostPrivateInstances")} -

-

- {t("hostPrivateInstancesDescription")} -

-
- */} -
-
-
- -
- - - - {t("futureEval")} - -
- } - subtitle={t("futureEvalCardSubtitle")} - variant="futureEval" - arrowClassName="opacity-50" - > -
-
-

- {t("modelLeaderboard")} -

-

- {t("futureEvalCardModelLeaderboardDescriptionShort")} -

-
-
-

- {t("futureEvalCardBuildBotTitle")} -

-

- {t("futureEvalCardBuildBotDescription")} -

-
-
- -
-
- -
- ); -}; - -export default HeroCTAs; diff --git a/front_end/src/app/(main)/(home)/components/hero_futureeval_symbol.tsx b/front_end/src/app/(main)/(home)/components/hero_futureeval_symbol.tsx new file mode 100644 index 0000000000..ffd1c4355a --- /dev/null +++ b/front_end/src/app/(main)/(home)/components/hero_futureeval_symbol.tsx @@ -0,0 +1,44 @@ +import { FC } from "react"; + +const HeroFutureEvalSymbol: FC<{ className?: string }> = ({ className }) => ( + +); + +export default HeroFutureEvalSymbol; diff --git a/front_end/src/app/(main)/(home)/components/hero_globe_background.tsx b/front_end/src/app/(main)/(home)/components/hero_globe_background.tsx new file mode 100644 index 0000000000..18c6a20bbc --- /dev/null +++ b/front_end/src/app/(main)/(home)/components/hero_globe_background.tsx @@ -0,0 +1,38 @@ +"use client"; + +import dynamic from "next/dynamic"; +import { FC } from "react"; + +const DitheringShader = dynamic( + () => + import("@paper-design/shaders-react").then((mod) => { + const { Dithering } = mod; + const Wrapper: FC = () => ( + + ); + Wrapper.displayName = "DitheringWrapper"; + return Wrapper; + }), + { ssr: false } +); + +const HeroGlobeBackground: FC = () => { + return ( +
+
+ +
+
+ ); +}; + +export default HeroGlobeBackground; diff --git a/front_end/src/app/(main)/(home)/components/hero_section.tsx b/front_end/src/app/(main)/(home)/components/hero_section.tsx new file mode 100644 index 0000000000..941a8cc29e --- /dev/null +++ b/front_end/src/app/(main)/(home)/components/hero_section.tsx @@ -0,0 +1,214 @@ +"use client"; + +import { faArrowRight } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import Link from "next/link"; +import { useTranslations } from "next-intl"; +import { FC, useEffect, useState } from "react"; + +import { useAuth } from "@/contexts/auth_context"; +import ClientMiscApi from "@/services/api/misc/misc.client"; +import cn from "@/utils/core/cn"; +import { abbreviatedNumber } from "@/utils/formatters/number"; + +import HeroFutureEvalSymbol from "./hero_futureeval_symbol"; +import HeroGlobeBackground from "./hero_globe_background"; +import MetaculusStorefrontLogo from "./metaculus_storefront_logo"; +import RadiantLogo from "./radiant_logo"; + +const HeroSection: FC = () => { + const t = useTranslations(); + const { user } = useAuth(); + const logoHref = user ? "/questions/" : "/"; + + const [stats, setStats] = useState({ + predictions: 2133159, + questions: 17357, + years_of_predictions: 10, + }); + + useEffect(() => { + ClientMiscApi.getSiteStats() + .then((s) => { + if (s) { + setStats({ + predictions: s.predictions, + questions: s.questions, + years_of_predictions: s.years_of_predictions, + }); + } + }) + .catch(() => {}); + }, []); + + return ( +
+
+ +
+ +
+ {/* Logo + title */} + + +
+ + Metaculus + + + {t("clarityInAComplexWorld")} + +
+ + + {/* CTA cards */} +
+
+ {/* Forecasting Platform */} + +
+
+
+ + {t("forecastingPlatform")} + + +
+

+ {t("collectiveIntelligenceForPublicGood")} +

+
+
+ + + {abbreviatedNumber(stats.predictions)}+ + {" "} + {t("predictions")} + + + + {abbreviatedNumber(stats.questions)}+ + {" "} + {t("forecastingQuestions")} + + + + {t("yearsOfPredictions", { + count: stats.years_of_predictions, + })} + + +
+ + + {/* Business Solutions */} + +
+
+
+ + {t("businessSolutions")} + + +
+

+ {t("forInformedDecisionMaking")} +

+
+
+ + {t("hire")} {t("proForecasters")} + + + {t("run")} {t("tournaments")} + + + {t("host")} {t("privateInstances")} + +
+ +
+ + {/* FutureEval + Radiant banners */} +
+ {/* FutureEval banner */} + +
+
+
+ + + FutureEval + +
+ +
+

+ {t("measuringForecastingAccuracyOfAI")} +

+ + + + {/* Radiant banner */} + +
+
+
+ + + {t("radiant")} + +
+ +
+

+ {t("mapTheFutureBeforeYouBuildIt")} +

+ + +
+
+
+
+ ); +}; + +export default HeroSection; diff --git a/front_end/src/app/(main)/(home)/components/homepage_forecasts.tsx b/front_end/src/app/(main)/(home)/components/homepage_forecasts.tsx deleted file mode 100644 index 287e80f038..0000000000 --- a/front_end/src/app/(main)/(home)/components/homepage_forecasts.tsx +++ /dev/null @@ -1,152 +0,0 @@ -"use client"; - -import { faArrowRight } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import Link from "next/link"; -import { useTranslations } from "next-intl"; -import { FC, useRef, useState, useTransition } from "react"; - -import Button from "@/components/ui/button"; -import { Tabs, TabsList, TabsTab } from "@/components/ui/tabs"; -import { useBreakpoint } from "@/hooks/tailwind"; -import ClientPostsApi from "@/services/api/posts/posts.client"; -import { PostWithForecasts } from "@/types/post"; -import cn from "@/utils/core/cn"; -import { isConditionalPost, isNotebookPost } from "@/utils/questions/helpers"; - -import { FILTERS, TABS, TabId } from "./homepage_filters"; -import HomepagePostCard from "./homepage_post_card"; - -const MOBILE_POSTS_INCREMENT = 3; - -type Props = { - initialPosts: PostWithForecasts[]; - className?: string; -}; - -const filterValidPosts = (posts: PostWithForecasts[]): PostWithForecasts[] => - posts.filter((post) => !isConditionalPost(post) && !isNotebookPost(post)); - -const HomePageForecasts: FC = ({ initialPosts, className }) => { - const t = useTranslations(); - const [activeTab, setActiveTab] = useState("news"); - const activeTabRef = useRef(activeTab); - const filteredInitialPosts = filterValidPosts(initialPosts); - const [posts, setPosts] = useState(filteredInitialPosts); - const [isPending, startTransition] = useTransition(); - const [cachedPosts, setCachedPosts] = useState< - Partial> - >({ - news: filteredInitialPosts, - }); - const [mobileVisibleCount, setMobileVisibleCount] = useState( - MOBILE_POSTS_INCREMENT - ); - - const tabLabels: Record = { - news: t("inTheNews"), - popular: t("popular"), - new: t("new"), - }; - - const handleTabChange = (tabId: string) => { - const id = tabId as TabId; - if (id === activeTab) return; - - setActiveTab(id); - activeTabRef.current = id; - setMobileVisibleCount(MOBILE_POSTS_INCREMENT); - - if (cachedPosts[id]) { - setPosts(cachedPosts[id] ?? []); - return; - } - - startTransition(async () => { - const response = await ClientPostsApi.getPostsWithCPForHomepage( - FILTERS[id] - ); - const newPosts = filterValidPosts(response.results); - - if (activeTabRef.current !== id) { - return; - } - - setCachedPosts((prev) => ({ ...prev, [id]: newPosts })); - setPosts(newPosts); - }); - }; - - const isSmallScreen = !useBreakpoint("md"); - const visiblePosts = isSmallScreen - ? posts.slice(0, mobileVisibleCount) - : posts; - const hasMorePosts = isSmallScreen && mobileVisibleCount < posts.length; - - const handleLoadMore = () => { - setMobileVisibleCount((prev) => prev + MOBILE_POSTS_INCREMENT); - }; - - return ( -
- - -
- {TABS.map((tab) => ( - - !isActive - ? "hover:bg-blue-400 dark:hover:bg-blue-400-dark text-blue-800 dark:text-blue-800-dark" - : "" - } - scrollOnSelect={false} - > - {tabLabels[tab.id]} - - ))} -
- - {t("feed")} - {t("questionFeed")} - - -
-
- -
- {visiblePosts.map((post) => ( - - ))} -
- - {hasMorePosts && ( -
- -
- )} -
- ); -}; - -export default HomePageForecasts; diff --git a/front_end/src/app/(main)/(home)/components/homepage_post_card.tsx b/front_end/src/app/(main)/(home)/components/homepage_post_card.tsx index 2695c9518d..c6641bb8d6 100644 --- a/front_end/src/app/(main)/(home)/components/homepage_post_card.tsx +++ b/front_end/src/app/(main)/(home)/components/homepage_post_card.tsx @@ -30,20 +30,23 @@ const HomepagePostCard: FC = ({ post, className }) => {
-
-
+
+
+ -

@@ -51,11 +54,13 @@ const HomepagePostCard: FC = ({ post, className }) => {

{isQuestionPost(post) && !isMultipleChoicePost(post) && ( - +
+ +
)} {(isGroupOfQuestionsPost(post) || isMultipleChoicePost(post)) && ( - + )}
diff --git a/front_end/src/app/(main)/(home)/components/metaculus_storefront_logo.tsx b/front_end/src/app/(main)/(home)/components/metaculus_storefront_logo.tsx new file mode 100644 index 0000000000..e25fb45a8c --- /dev/null +++ b/front_end/src/app/(main)/(home)/components/metaculus_storefront_logo.tsx @@ -0,0 +1,21 @@ +import { FC, SVGProps } from "react"; + +const MetaculusStorefrontLogo: FC> = (props) => ( + + + + +); + +export default MetaculusStorefrontLogo; diff --git a/front_end/src/app/(main)/(home)/components/newsletter_subscription.tsx b/front_end/src/app/(main)/(home)/components/newsletter_subscription.tsx deleted file mode 100644 index 6360e9d96d..0000000000 --- a/front_end/src/app/(main)/(home)/components/newsletter_subscription.tsx +++ /dev/null @@ -1,114 +0,0 @@ -"use client"; - -import { faCheck } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { useTranslations } from "next-intl"; -import { FC, FormEvent, useState } from "react"; - -import cn from "@/utils/core/cn"; - -import { subscribeToNewsletter } from "../../actions"; - -const BENEFITS = [ - "newsletterBenefit1", - "newsletterBenefit2", - "newsletterBenefit3", -] as const; - -const NewsletterSubscription: FC = () => { - const t = useTranslations(); - const [email, setEmail] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [isSuccess, setIsSuccess] = useState(false); - const [error, setError] = useState(null); - - const handleSubmit = async (e: FormEvent) => { - e.preventDefault(); - if (!email.trim()) return; - - setIsLoading(true); - setError(null); - - try { - await subscribeToNewsletter(email); - setIsSuccess(true); - setEmail(""); - } catch { - setError(t("newsletterError")); - } finally { - setIsLoading(false); - } - }; - - return ( -
-
-
-
-

- {t("newsletterTitle")} -

-

- {t("newsletterDescription")} -

-
- -
- {BENEFITS.map((benefitKey) => ( -
- - - {t(benefitKey)} - -
- ))} -
-
- - {isSuccess ? ( -
- {t("newsletterSuccess")} -
- ) : ( -
-
- setEmail(e.target.value)} - placeholder={t("newsletterPlaceholder")} - className={cn( - "h-10 w-full rounded-lg border-[1.5px] border-transparent bg-mint-200 px-3.5 text-sm font-medium text-mint-800 placeholder:text-mint-700 focus:border-mint-700 focus:outline-none dark:bg-mint-200-dark dark:text-mint-800-dark dark:placeholder:text-mint-700-dark dark:focus:border-mint-700-dark sm:w-[352px]", - error && - "border-red-500 focus:border-red-500 dark:border-red-500-dark dark:focus:border-red-500-dark" - )} - required - disabled={isLoading} - /> - {error && ( - - {error} - - )} -
- -
- )} -
-
- ); -}; - -export default NewsletterSubscription; diff --git a/front_end/src/app/(main)/(home)/components/radiant_logo.tsx b/front_end/src/app/(main)/(home)/components/radiant_logo.tsx new file mode 100644 index 0000000000..6fd5886b59 --- /dev/null +++ b/front_end/src/app/(main)/(home)/components/radiant_logo.tsx @@ -0,0 +1,18 @@ +import { FC, SVGProps } from "react"; + +const RadiantLogo: FC> = (props) => ( + + + + +); + +export default RadiantLogo; diff --git a/front_end/src/app/(main)/(home)/components/research_and_updates.tsx b/front_end/src/app/(main)/(home)/components/research_and_updates.tsx deleted file mode 100644 index 551137dd80..0000000000 --- a/front_end/src/app/(main)/(home)/components/research_and_updates.tsx +++ /dev/null @@ -1,163 +0,0 @@ -"use server"; -import { intlFormat } from "date-fns"; -import Image from "next/image"; -import Link from "next/link"; -import { getLocale, getTranslations } from "next-intl/server"; -import { FC } from "react"; - -import WithServerComponentErrorBoundary from "@/components/server_component_error_boundary"; -import Button from "@/components/ui/button"; -import { NotebookPost } from "@/types/post"; -import cn from "@/utils/core/cn"; -import { estimateReadingTime, getMarkdownSummary } from "@/utils/markdown"; -import { getPostLink } from "@/utils/navigation"; - -const CARD_GRADIENTS = [ - "radial-gradient(ellipse at center, #ede28f 0%, #c5b3c2 50%, #9d83f5 100%)", - "radial-gradient(ellipse at center, #b5ed8f 0%, #d5b889 50%, #f58383 100%)", - "radial-gradient(ellipse at center, #ed8fd9 0%, #b8c2c7 50%, #83f5b4 100%)", - "radial-gradient(ellipse at center, #ed8f8f 0%, #f1bf89 50%, #f5ef83 100%)", -]; - -type Props = { - posts: NotebookPost[]; - className?: string; -}; - -const ResearchAndUpdates: FC = async ({ posts, className }) => { - const t = await getTranslations(); - const locale = await getLocale(); - - return ( -
-
-
-

- {t("researchAndUpdates")} -

-

- {t("partnersUseForecasts")} -

-
- -
- -
- {posts.slice(0, 4).map((post, index) => ( - - ))} -
-
- ); -}; - -type PostCardProps = { - post: NotebookPost; - index: number; - locale: string; -}; - -const NotebookCard: FC = async ({ post, index, locale }) => { - const t = await getTranslations(); - const { - title, - created_at, - id, - notebook, - slug, - author_username, - comment_count = 0, - } = post; - - const readingTime = estimateReadingTime(notebook.markdown); - const summary = - notebook.feed_tile_summary || - getMarkdownSummary({ - markdown: notebook.markdown, - width: 280, - height: 60, - withLinks: false, - }); - - const gradient = CARD_GRADIENTS[index % CARD_GRADIENTS.length]; - - return ( - -
- {notebook.image_url ? ( - - ) : ( -
- )} -
- -
-
- - {intlFormat( - new Date(created_at), - { - year: "numeric", - month: "short", - day: "numeric", - }, - { locale } - )} - -

- {title} -

-

- {summary} -

-
- -
- - {author_username} - -
- - {comment_count} {t("commentsWithCount", { count: comment_count })} - - - - {t("estimatedReadingTime", { minutes: readingTime })} - -
-
-
- - ); -}; - -export default WithServerComponentErrorBoundary(ResearchAndUpdates); diff --git a/front_end/src/app/(main)/(home)/components/staff_picks.tsx b/front_end/src/app/(main)/(home)/components/staff_picks.tsx index 91b5241422..cd1f78eaf9 100644 --- a/front_end/src/app/(main)/(home)/components/staff_picks.tsx +++ b/front_end/src/app/(main)/(home)/components/staff_picks.tsx @@ -17,8 +17,8 @@ type Props = { const StaffPicks: FC = ({ items }) => { const t = useTranslations(); return ( -
-

+
+

{t("staffPicks")}

{items.map((item, idx) => ( @@ -26,7 +26,7 @@ const StaffPicks: FC = ({ items }) => { key={`staff-pick-${idx}`} href={item.url} className={cn( - "flex shrink-0 items-center gap-1 rounded-full border-0 bg-blue-400 py-2 pl-3 pr-4 text-xs font-medium leading-3 text-blue-700 no-underline transition-colors hover:bg-blue-500 dark:bg-blue-400-dark dark:text-blue-700-dark dark:hover:bg-blue-500-dark" + "flex shrink-0 items-center gap-1 rounded-full border-0 bg-gray-0 py-2 pl-3 pr-4 text-xs font-medium leading-3 text-blue-700 no-underline transition-colors hover:bg-blue-400" )} > @@ -36,9 +36,7 @@ const StaffPicks: FC = ({ items }) => { item.emoji )} - - {item.name} - + {item.name} ))}
diff --git a/front_end/src/app/(main)/(home)/components/tournaments_section.tsx b/front_end/src/app/(main)/(home)/components/tournaments_section.tsx deleted file mode 100644 index b96954a691..0000000000 --- a/front_end/src/app/(main)/(home)/components/tournaments_section.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { getTranslations } from "next-intl/server"; -import { FC } from "react"; - -import LiveTournamentCard from "@/app/(main)/(tournaments)/tournaments/components/tournaments_grid/live_tournament_card"; -import WithServerComponentErrorBoundary from "@/components/server_component_error_boundary"; -import Button from "@/components/ui/button"; -import ServerProjectsApi from "@/services/api/projects/projects.server"; -import { TournamentType } from "@/types/projects"; -import cn from "@/utils/core/cn"; - -const TournamentsSection: FC<{ className?: string }> = async ({ - className, -}) => { - const t = await getTranslations(); - const allTournaments = (await ServerProjectsApi.getTournaments()).filter( - (t) => t.is_ongoing && t.type == TournamentType.Tournament - ); - const tournaments = allTournaments.filter((t) => t.show_on_homepage); - - return ( -
-
-
-

- {t("forecasting")} {t("tournaments")} -

-

- {t("joinTournaments")} -

-
- -
-
- {tournaments.map((tournament) => ( - - ))} -
-
- ); -}; - -export default WithServerComponentErrorBoundary(TournamentsSection); diff --git a/front_end/src/app/(main)/(home)/components/why_metaculus.tsx b/front_end/src/app/(main)/(home)/components/why_metaculus.tsx deleted file mode 100644 index 7652d772ca..0000000000 --- a/front_end/src/app/(main)/(home)/components/why_metaculus.tsx +++ /dev/null @@ -1,166 +0,0 @@ -"use client"; - -import { useTranslations } from "next-intl"; -import React, { FC, useEffect, useState } from "react"; - -import ClientMiscApi from "@/services/api/misc/misc.client"; -import cn from "@/utils/core/cn"; -import { abbreviatedNumber } from "@/utils/formatters/number"; - -import { - NasdaqLogo, - ForbesLogo, - TheAtlanticLogo, - AeiLogo, - TheEconomistLogo, - BloombergLogo, -} from "./featured-in-logos"; - -const FEATURED_IN = [ - { - href: "https://www.nasdaq.com/articles/how-crypto-can-help-secure-ai", - label: "Nasdaq", - component: ( - - ), - }, - { - href: "https://www.forbes.com/sites/stevenwolfepereira/2025/12/08/building-a-one-person-unicorn-this-startup-just-raised-87m-to-help/", - label: "Forbes", - component: ( - - ), - }, - { - href: "https://archive.is/0O588", - label: "The Atlantic", - component: ( - - ), - }, - { - href: "https://www.aei.org/articles/the-great-ai-forecasting-divide/1", - label: "AEI", - component: ( - - ), - }, - { - href: "https://www.economist.com/finance-and-economics/2023/05/23/what-would-humans-do-in-a-world-of-super-ai", - label: "The Economist", - component: , - }, - { - href: "https://www.bloomberg.com/opinion/articles/2024-03-24/can-sam-altman-make-ai-smart-enough-to-answer-these-6-questions", - label: "Bloomberg", - component: ( - - ), - }, -]; - -const fetchSiteStats = async () => { - try { - return await ClientMiscApi.getSiteStats(); - } catch { - // silently fail - return null; - } -}; - -const WhyMetaculus: FC<{ className?: string }> = ({ className }) => { - const t = useTranslations(); - const [siteStats, setSiteStats] = useState({ - predictions: 2133159, - questions: 17357, - years_of_predictions: 10, - }); - - useEffect(() => { - fetchSiteStats().then((stats) => { - if (!stats) { - return; - } - - setSiteStats({ - predictions: stats.predictions, - questions: stats.questions, - years_of_predictions: stats.years_of_predictions, - }); - }); - }, []); - - return ( -
- {/* Left Column: Description & Stats */} -
-

- - Metaculus - {" "} - is an{" "} - - online forecasting platform - {" "} - focusing on{" "} - - topics of global importance - - . -

- -
- - - -
-
- - {/* Right Column: Featured In */} -
- - {t("featuredIn")} - -
- {FEATURED_IN.map((item) => ( - - {item.component} - - ))} -
-
-
- ); -}; - -const Stat: FC<{ number: string; label: string }> = ({ number, label }) => ( -
- - {number} - - {label} -
-); - -export default WhyMetaculus; diff --git a/front_end/src/app/(main)/(home)/page.tsx b/front_end/src/app/(main)/(home)/page.tsx index 8f8fb198f5..1c53ca1674 100644 --- a/front_end/src/app/(main)/(home)/page.tsx +++ b/front_end/src/app/(main)/(home)/page.tsx @@ -1,25 +1,18 @@ import { redirect } from "next/navigation"; -import { Suspense } from "react"; import OnboardingCheck from "@/components/onboarding/onboarding_check"; -import LoadingIndicator from "@/components/ui/loading_indicator"; import serverMiscApi from "@/services/api/misc/misc.server"; import ServerPostsApi from "@/services/api/posts/posts.server"; -import ServerProjectsApi from "@/services/api/projects/projects.server"; -import { NotebookPost } from "@/types/post"; import { getPublicSettings } from "@/utils/public_settings.server"; import { convertSidebarItem } from "@/utils/sidebar"; -import AllCategoriesSection from "./components/all_categories_section"; import EmailConfirmation from "./components/email_confirmation"; -import HeroCTAs from "./components/hero_ctas"; +import FeaturedInMarquee from "./components/featured_in_marquee"; +import ForceLightMode from "./components/force_light_mode"; +import ForecastsCarouselSection from "./components/forecasts_carousel_section"; +import HeroSection from "./components/hero_section"; import { FILTERS } from "./components/homepage_filters"; -import HomePageForecasts from "./components/homepage_forecasts"; -import NewsletterSubscription from "./components/newsletter_subscription"; -import ResearchAndUpdates from "./components/research_and_updates"; import StaffPicks from "./components/staff_picks"; -import TournamentsSection from "./components/tournaments_section"; -import WhyMetaculus from "./components/why_metaculus"; export default async function Home() { const { PUBLIC_LANDING_PAGE_URL } = getPublicSettings(); @@ -28,61 +21,27 @@ export default async function Home() { return redirect(PUBLIC_LANDING_PAGE_URL); } - const [sidebarItems, homepagePosts, categories, initialNewsPosts] = - await Promise.all([ - serverMiscApi.getSidebarItems(), - ServerPostsApi.getPostsForHomepage(), - ServerProjectsApi.getHomepageCategories(), - ServerPostsApi.getPostsWithCP(FILTERS.news), - ]); - - const postNotebooks = homepagePosts.filter( - (post) => !!post.notebook - ) as unknown as NotebookPost[]; + const [sidebarItems, initialNewsPosts] = await Promise.all([ + serverMiscApi.getSidebarItems(), + ServerPostsApi.getPostsWithCP(FILTERS.news), + ]); const hotTopics = sidebarItems .filter(({ section }) => section === "hot_topics") .map((item) => convertSidebarItem(item)); - const contentWidthClassNames = "2xl:max-w-[1352px] w-full mx-auto px-4"; - return ( -
+
+ + - -
- -
-
-
- -
-
- }> -
- -
-
- }> -
- -
-
- }> - - - + +
); } diff --git a/front_end/src/app/(main)/components/footer.tsx b/front_end/src/app/(main)/components/footer.tsx index 51977bcd9f..a48f27dd9c 100644 --- a/front_end/src/app/(main)/components/footer.tsx +++ b/front_end/src/app/(main)/components/footer.tsx @@ -10,7 +10,7 @@ import { ListboxOption, } from "@headlessui/react"; import Link from "next/link"; -import { useRouter } from "next/navigation"; +import { usePathname, useRouter } from "next/navigation"; import { useTranslations, useLocale } from "next-intl"; import { usePostHog } from "posthog-js/react"; import { FC } from "react"; @@ -267,6 +267,8 @@ const ThemeSelector: FC = () => { const Footer: FC = () => { const t = useTranslations(); const { setCurrentModal } = useModal(); + const pathname = usePathname(); + const isHomepage = pathname === "/"; const handleContactClick = () => setCurrentModal({ type: "contactUs" }); @@ -310,10 +312,12 @@ const Footer: FC = () => {

{/* Language and Theme selectors */} -
- - -
+ {!isHomepage && ( +
+ + +
+ )}
{/* Right section - Link columns */} diff --git a/front_end/src/app/(main)/components/layout_content_wrapper.tsx b/front_end/src/app/(main)/components/layout_content_wrapper.tsx new file mode 100644 index 0000000000..08ff96f78c --- /dev/null +++ b/front_end/src/app/(main)/components/layout_content_wrapper.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { usePathname } from "next/navigation"; +import { FC, ReactNode } from "react"; + +import cn from "@/utils/core/cn"; +import { getWithDefaultHeader } from "@/utils/navigation"; + +type Props = { + children: ReactNode; +}; + +const LayoutContentWrapper: FC = ({ children }) => { + const pathname = usePathname(); + const hasHeader = getWithDefaultHeader(pathname); + + return ( +
+ {children} +
+ ); +}; + +export default LayoutContentWrapper; diff --git a/front_end/src/app/(main)/layout.tsx b/front_end/src/app/(main)/layout.tsx index f0554e84d9..765fa9d097 100644 --- a/front_end/src/app/(main)/layout.tsx +++ b/front_end/src/app/(main)/layout.tsx @@ -12,6 +12,7 @@ import CookiesBanner from "./components/cookies_banner"; import Footer from "./components/footer"; import GlobalHeader from "./components/headers/global_header"; import ImpersonationBanner from "./components/impersonation_banner"; +import LayoutContentWrapper from "./components/layout_content_wrapper"; import VersionChecker from "./components/version_checker"; config.autoAddCss = false; @@ -32,7 +33,7 @@ export default async function RootLayout({ const isImpersonating = authManager.isImpersonating(); return ( -
+ {isImpersonating && } @@ -47,6 +48,6 @@ export default async function RootLayout({ )} -
+ ); } diff --git a/front_end/src/components/consumer_post_card/group_forecast_card/forecast_card_wrapper.tsx b/front_end/src/components/consumer_post_card/group_forecast_card/forecast_card_wrapper.tsx index 947f5c8bb4..2154e2ca44 100644 --- a/front_end/src/components/consumer_post_card/group_forecast_card/forecast_card_wrapper.tsx +++ b/front_end/src/components/consumer_post_card/group_forecast_card/forecast_card_wrapper.tsx @@ -9,6 +9,7 @@ type Props = { expanded?: boolean; onExpand?: () => void; hideOthersValue?: boolean; + compact?: boolean; }; const ForecastCardWrapper: FC> = ({ @@ -17,13 +18,19 @@ const ForecastCardWrapper: FC> = ({ expanded = false, onExpand, hideOthersValue = false, + compact = false, children, }) => { const t = useTranslations(); const showRow = !expanded && otherItemsCount > 0; return ( -
+
{children} {showRow && ( @@ -32,7 +39,10 @@ const ForecastCardWrapper: FC> = ({ onClick={onExpand} aria-pressed={false} className={cn( - "group relative flex h-8 w-full items-center justify-between gap-3 rounded-[8px] px-[10px] py-1", + "group relative flex w-full items-center justify-between gap-3 rounded-[8px]", + compact + ? "h-6 px-2 py-0.5 md:h-8 md:px-[10px] md:py-1" + : "h-8 px-[10px] py-1", "border border-blue-400 bg-white", "dark:border-blue-400-dark dark:bg-transparent" )} @@ -40,6 +50,7 @@ const ForecastCardWrapper: FC> = ({ > = ({ {!hideOthersValue && ( - + {Math.round(othersTotal)}% )} diff --git a/front_end/src/components/consumer_post_card/group_forecast_card/forecast_choice_bar.tsx b/front_end/src/components/consumer_post_card/group_forecast_card/forecast_choice_bar.tsx index 755c217cca..10dab1bcb0 100644 --- a/front_end/src/components/consumer_post_card/group_forecast_card/forecast_choice_bar.tsx +++ b/front_end/src/components/consumer_post_card/group_forecast_card/forecast_choice_bar.tsx @@ -24,6 +24,7 @@ type Props = { isBordered?: boolean; unit?: string; forceColorful?: boolean; + compact?: boolean; }; const WIDTH_ADJUSTMENT = 2; @@ -39,6 +40,7 @@ const ForecastChoiceBar: FC = ({ isBordered = false, unit, forceColorful = false, + compact = false, }) => { const t = useTranslations(); const { getThemeColor } = useAppTheme(); @@ -49,7 +51,10 @@ const ForecastChoiceBar: FC = ({ return (
= ({ {isCpRevealed && (
= ({ post }) => { +const GroupForecastCard: FC = ({ post, compact }) => { // Check forecast availability for group posts const forecastAvailability = post.group_of_questions ? getGroupForecastAvailability(post.group_of_questions.questions) @@ -46,13 +47,13 @@ const GroupForecastCard: FC = ({ post }) => { isMultipleChoicePost(post) || checkGroupOfQuestionsPostType(post, QuestionType.Binary) ) { - return ; + return ; } if ( checkGroupOfQuestionsPostType(post, QuestionType.Numeric) || checkGroupOfQuestionsPostType(post, QuestionType.Discrete) ) { - return ; + return ; } if ( post.group_of_questions && diff --git a/front_end/src/components/consumer_post_card/group_forecast_card/numeric_forecast_card.tsx b/front_end/src/components/consumer_post_card/group_forecast_card/numeric_forecast_card.tsx index 061bec8e04..578bafd4c0 100644 --- a/front_end/src/components/consumer_post_card/group_forecast_card/numeric_forecast_card.tsx +++ b/front_end/src/components/consumer_post_card/group_forecast_card/numeric_forecast_card.tsx @@ -21,9 +21,10 @@ import ForecastChoiceBar from "./forecast_choice_bar"; type Props = { post: PostWithForecasts; forceColorful?: boolean; + compact?: boolean; }; -const NumericForecastCard: FC = ({ post, forceColorful }) => { +const NumericForecastCard: FC = ({ post, forceColorful, compact }) => { const locale = useLocale(); const t = useTranslations(); const [expanded, setExpanded] = useState(false); @@ -85,6 +86,7 @@ const NumericForecastCard: FC = ({ post, forceColorful }) => { expanded={expanded} onExpand={() => setExpanded(true)} hideOthersValue + compact={compact} > {visibleChoices.map( ({ @@ -143,6 +145,7 @@ const NumericForecastCard: FC = ({ post, forceColorful }) => { color={color} unit={unit} forceColorful={forceColorful} + compact={compact} /> ); } diff --git a/front_end/src/components/consumer_post_card/group_forecast_card/percentage_forecast_card.tsx b/front_end/src/components/consumer_post_card/group_forecast_card/percentage_forecast_card.tsx index 1370f5e8d3..64891034d6 100644 --- a/front_end/src/components/consumer_post_card/group_forecast_card/percentage_forecast_card.tsx +++ b/front_end/src/components/consumer_post_card/group_forecast_card/percentage_forecast_card.tsx @@ -22,9 +22,14 @@ import ForecastChoiceBar from "./forecast_choice_bar"; type Props = { post: PostWithForecasts; forceColorful?: boolean; + compact?: boolean; }; -const PercentageForecastCard: FC = ({ post, forceColorful }) => { +const PercentageForecastCard: FC = ({ + post, + forceColorful, + compact, +}) => { const locale = useLocale(); const t = useTranslations(); const [expanded, setExpanded] = useState(false); @@ -99,6 +104,7 @@ const PercentageForecastCard: FC = ({ post, forceColorful }) => { expanded={expanded} onExpand={() => setExpanded(true)} hideOthersValue={isGroupBinary} + compact={compact} > {visible.map((choice) => ( = ({ post, forceColorful }) => { color={choice.color} isBordered={true} forceColorful={forceColorful} + compact={compact} /> ))} diff --git a/front_end/src/utils/navigation.ts b/front_end/src/utils/navigation.ts index 4945ff3713..b2b48c3181 100644 --- a/front_end/src/utils/navigation.ts +++ b/front_end/src/utils/navigation.ts @@ -168,6 +168,7 @@ export const getProjectSlug = (project: Pick) => { }; export const getWithDefaultHeader = (pathname: string): boolean => + pathname !== "/" && !pathname.match(/^\/questions\/(\d+)(\/.*)?$/) && !pathname.match(/^\/notebooks\/(\d+)(\/.*)?$/) && !pathname.startsWith("/c/") &&