diff --git a/VocaDbWeb/Controllers/ReactController.cs b/VocaDbWeb/Controllers/ReactController.cs new file mode 100644 index 0000000000..8ae74c7ec9 --- /dev/null +++ b/VocaDbWeb/Controllers/ReactController.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc; + +namespace VocaDb.Web.Controllers +{ + public class ReactController : Controller + { + public IActionResult Index() + { + return View(); + } + } +} diff --git a/VocaDbWeb/Scripts/App.tsx b/VocaDbWeb/Scripts/App.tsx new file mode 100644 index 0000000000..cb716661e7 --- /dev/null +++ b/VocaDbWeb/Scripts/App.tsx @@ -0,0 +1,9 @@ +import React from 'react'; + +import './i18n'; + +const App = (): React.ReactElement => { + return <>; +}; + +export default App; diff --git a/VocaDbWeb/Scripts/i18n.ts b/VocaDbWeb/Scripts/i18n.ts new file mode 100644 index 0000000000..6e9987eee9 --- /dev/null +++ b/VocaDbWeb/Scripts/i18n.ts @@ -0,0 +1,21 @@ +import i18n from 'i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import Backend from 'i18next-http-backend'; +import { initReactI18next } from 'react-i18next'; + +i18n + .use(Backend) + .use(LanguageDetector) + .use(initReactI18next) + .init({ + load: 'languageOnly', + fallbackLng: 'en', + + interpolation: { + escapeValue: false, + }, + + react: { + useSuspense: false, + }, + }); diff --git a/VocaDbWeb/Scripts/index.tsx b/VocaDbWeb/Scripts/index.tsx new file mode 100644 index 0000000000..30b5d776ad --- /dev/null +++ b/VocaDbWeb/Scripts/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App'; + +const app = document.getElementById('app'); + +ReactDOM.render( + + + , + app, +); diff --git a/VocaDbWeb/Startup.cs b/VocaDbWeb/Startup.cs index eb8d6f3f71..f8b2500d57 100644 --- a/VocaDbWeb/Startup.cs +++ b/VocaDbWeb/Startup.cs @@ -370,6 +370,8 @@ void HandleHttpError(int code, string? description = null, string? msg = null) endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); + + endpoints.MapFallbackToController(action: "Index", controller: "React"); }); } } diff --git a/VocaDbWeb/Views/React/Index.cshtml b/VocaDbWeb/Views/React/Index.cshtml new file mode 100644 index 0000000000..4422515b0e --- /dev/null +++ b/VocaDbWeb/Views/React/Index.cshtml @@ -0,0 +1,43 @@ +@using System.Globalization +@using VocaDb.Model.DataContracts.Users +@using VocaDb.Model.Domain.Globalization +@using VocaDb.Model.Helpers +@using VocaDb.Model.Utils +@using VocaDb.Web.Models.Shared +@inherits VocaDbPage +@addTagHelper *, VocaDb.ReMikus + +@{ + Layout = null; + + var stylesheet = Login.IsLoggedIn && !string.IsNullOrEmpty(Login.User.Stylesheet) ? Login.User.Stylesheet : Config.SiteSettings.DefaultStylesheet; +} + + + + + + + Vocaloid Database + + + + @if (!string.IsNullOrEmpty(stylesheet)) + { + + } + + + + + + + + +
+ + + + + + diff --git a/VocaDbWeb/tsconfig.json b/VocaDbWeb/tsconfig.json index 99023ee011..8353af3e44 100644 --- a/VocaDbWeb/tsconfig.json +++ b/VocaDbWeb/tsconfig.json @@ -11,6 +11,7 @@ "forceConsistentCasingInFileNames": true, "baseUrl": "./", "paths": { + "@Components/*": ["Scripts/Components/*"], "@DataContracts/*": ["Scripts/DataContracts/*"], "@Helpers/*": ["Scripts/Helpers/*"], "@KnockoutExtensions/*": ["Scripts/KnockoutExtensions/*"], diff --git a/VocaDbWeb/webpack.mix.js b/VocaDbWeb/webpack.mix.js index 36de509c49..9be365d31e 100644 --- a/VocaDbWeb/webpack.mix.js +++ b/VocaDbWeb/webpack.mix.js @@ -25,6 +25,7 @@ mix processCssUrls: false, }) .alias({ + '@Components': path.join(__dirname, 'Scripts/Components'), '@DataContracts': path.join(__dirname, 'Scripts/DataContracts'), '@Helpers': path.join(__dirname, 'Scripts/Helpers'), '@KnockoutExtensions': path.join(__dirname, 'Scripts/KnockoutExtensions'), @@ -78,7 +79,10 @@ mix .styles( ['wwwroot/Scripts/jqwidgets27/styles/jqx.base.css'], 'wwwroot/Scripts/jqwidgets27/styles/css.css', - ); + ) + + .ts('Scripts/index.tsx', 'wwwroot/bundles') + .react(); if (mix.inProduction()) { mix.version();