);
-}
+};
-export default withRouter(SelectLang);
\ No newline at end of file
+export default SelectLang;
diff --git a/src/common/lib/HashLink.tsx b/src/common/lib/HashLink.tsx
new file mode 100644
index 0000000..14ebd2e
--- /dev/null
+++ b/src/common/lib/HashLink.tsx
@@ -0,0 +1,53 @@
+import type { ComponentProps, MouseEvent } from 'react';
+import { Link, type To } from 'react-router';
+
+type LinkProps = ComponentProps;
+
+const RETRY_INTERVAL_MS = 16;
+const RETRY_COUNT = 20;
+
+const hashOf = (to: To): string => {
+ if (typeof to === 'string') {
+ const idx = to.indexOf('#');
+ return idx === -1 ? '' : to.slice(idx + 1);
+ }
+ return (to.hash ?? '').replace(/^#/, '');
+};
+
+const scrollToHash = (hash: string, remaining = RETRY_COUNT) => {
+ if (hash === '') {
+ return;
+ }
+ const id = decodeURIComponent(hash);
+ const target = document.getElementById(id) ?? document.querySelector(`[name="${CSS.escape(id)}"]`);
+ if (target !== null) {
+ target.scrollIntoView();
+ return;
+ }
+ // The target may not be in the DOM yet (pico pages fetch their content).
+ if (remaining > 0) {
+ setTimeout(() => {
+ scrollToHash(hash, remaining - 1);
+ }, RETRY_INTERVAL_MS);
+ }
+};
+
+/**
+ * A `` that also scrolls to the element named by the URL fragment.
+ * Replaces `react-router-hash-link`, which is unmaintained and still targets react-router v5.
+ */
+const HashLink = ({ onClick, to, ...rest }: LinkProps) => {
+ const handleClick = (e: MouseEvent) => {
+ onClick?.(e);
+ if (e.defaultPrevented) {
+ return;
+ }
+ // Let react-router commit the navigation before looking for the target.
+ setTimeout(() => {
+ scrollToHash(hashOf(to));
+ }, 0);
+ };
+ return ;
+};
+
+export default HashLink;
diff --git a/src/common/lib/LangFlag.tsx b/src/common/lib/LangFlag.tsx
index 191fb21..784c3fa 100644
--- a/src/common/lib/LangFlag.tsx
+++ b/src/common/lib/LangFlag.tsx
@@ -1,11 +1,9 @@
-import React from 'react';
-import { RouteComponentProps, withRouter } from 'react-router';
-import { Link } from 'react-router-dom';
-import { MultiLang } from '../../config';
+import { Link, useLocation } from 'react-router';
+import type { MultiLang } from '../../config';
import mlangEnglish from '../assets/images/mlang_english.gif';
import mlangJapanese from '../assets/images/mlang_japanese.gif';
-interface Props extends RouteComponentProps {
+interface Props {
lang: MultiLang;
}
@@ -23,16 +21,21 @@ const langResources = {
const LangFlag = (props: Props) => {
const { lang } = props;
- const params = new URLSearchParams(props.location.search);
+ const location = useLocation();
+ const params = new URLSearchParams(location.search);
const flagLang = lang === 'en' ? 'ja' : 'en';
params.set('ml_lang', flagLang);
- const url = props.location.pathname + '?' + params.toString();
+ const url = `${location.pathname}?${params.toString()}`;
return (
-
+
);
-}
+};
-
-export default withRouter(LangFlag);
+export default LangFlag;
diff --git a/src/common/lib/LinkImage.tsx b/src/common/lib/LinkImage.tsx
index 251e2cb..7581759 100644
--- a/src/common/lib/LinkImage.tsx
+++ b/src/common/lib/LinkImage.tsx
@@ -1,5 +1,5 @@
-import React, { Component } from 'react';
-import { Link } from 'react-router-dom';
+import { Component } from 'react';
+import { Link } from 'react-router';
interface Props {
url: string;
@@ -13,7 +13,6 @@ interface State {
}
class LinkImage extends Component {
-
constructor(props: Props) {
super(props);
this.state = {
@@ -26,14 +25,14 @@ class LinkImage extends Component {
handleMouseOver() {
const { imageHover } = this.props;
if (typeof imageHover !== 'undefined') {
- this.setState({ image: imageHover })
+ this.setState({ image: imageHover });
}
}
handleMouseOut() {
const { image: imageNormal, imageHover } = this.props;
if (typeof imageHover !== 'undefined') {
- this.setState({ image: imageNormal })
+ this.setState({ image: imageNormal });
}
}
@@ -42,13 +41,27 @@ class LinkImage extends Component {
const image = ;
if (url.match(/^(\/|\.)/) === null) {
return (
-
+
{image}
);
}
return (
-
+
{image}
);
diff --git a/src/common/lib/Loading.module.css b/src/common/lib/Loading.module.css
new file mode 100644
index 0000000..a339bdc
--- /dev/null
+++ b/src/common/lib/Loading.module.css
@@ -0,0 +1,27 @@
+.container {
+ display: flex;
+ justify-content: center;
+ align-content: center;
+ margin: 100px 0;
+}
+
+.spinner {
+ width: 120px;
+ height: 120px;
+ border: 8px solid #eeeeee;
+ border-top-color: #cccccc;
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .spinner {
+ animation-duration: 4s;
+ }
+}
diff --git a/src/common/lib/Loading.tsx b/src/common/lib/Loading.tsx
index 13ec917..af664c3 100644
--- a/src/common/lib/Loading.tsx
+++ b/src/common/lib/Loading.tsx
@@ -1,12 +1,9 @@
-import React from 'react';
-import Spinner from 'react-spinner-material';
+import styles from './Loading.module.css';
-const Loading = () => {
- return (
-
-
-
- );
-}
+const Loading = () => (
+
+
+
+);
-export default Loading;
\ No newline at end of file
+export default Loading;
diff --git a/src/common/lib/NoticeSiteHasBeenArchived.tsx b/src/common/lib/NoticeSiteHasBeenArchived.tsx
index c44a297..a9546dd 100644
--- a/src/common/lib/NoticeSiteHasBeenArchived.tsx
+++ b/src/common/lib/NoticeSiteHasBeenArchived.tsx
@@ -1,5 +1,4 @@
-import React from 'react';
-import { MultiLang } from '../../config';
+import type { MultiLang } from '../../config';
import Functions from '../../functions';
interface Props {
@@ -8,8 +7,9 @@ interface Props {
const NoticeSiteHasBeenArchived = (props: Props) => {
const { lang } = props;
- const notice = '[en]This site has been archived since FY2019 and is no longer updated.[/en][ja]このサイトは、2019年度よりアーカイブサイトとして運用されています。[/ja]';
+ const notice =
+ '[en]This site has been archived since FY2019 and is no longer updated.[/en][ja]このサイトは、2019年度よりアーカイブサイトとして運用されています。[/ja]';
return
{Functions.mlang('[en]This site promotes studies on the dynamic principles of brain functions through unifying experimental and computational approaches in cellular, local circuit, global network and behavioral levels. Our goal is to capture the autonomy and the creativity in living organisms which enlightens the complexity of nature and society.[/en][ja]当サイトでは、脳の動的原理を解明することを目的として、細胞、局所回路、脳全域、行動などの様々なレベルでの実験的計算論的アプローチの統合的な研究を推進します。これらの研究から生命の自律性と情報創成の原理を捉え、さらに自然や人間社会の複雑性の理解を進めることを目指します。[/ja]', lang)}
+
+
+ {Functions.mlang(
+ '[en]This site promotes studies on the dynamic principles of brain functions through unifying experimental and computational approaches in cellular, local circuit, global network and behavioral levels. Our goal is to capture the autonomy and the creativity in living organisms which enlightens the complexity of nature and society.[/en][ja]当サイトでは、脳の動的原理を解明することを目的として、細胞、局所回路、脳全域、行動などの様々なレベルでの実験的計算論的アプローチの統合的な研究を推進します。これらの研究から生命の自律性と情報創成の原理を捉え、さらに自然や人間社会の複雑性の理解を進めることを目指します。[/ja]',
+ lang
+ )}
+
- NIX-odML Global Workshop & Hackathon 2017 in Japan ({Functions.mlang('[en]Sept. 25-28, 2017[/en][ja]2017年9月25-28日[/ja]', lang)})
+
+ NIX-odML Global Workshop & Hackathon 2017 in Japan (
+ {Functions.mlang('[en]Sept. 25-28, 2017[/en][ja]2017年9月25-28日[/ja]', lang)})
+
);
-}
+};
-export default Welcome;
\ No newline at end of file
+export default Welcome;
diff --git a/src/database/Database.module.css b/src/database/Database.module.css
index 8ea86ba..9591694 100644
--- a/src/database/Database.module.css
+++ b/src/database/Database.module.css
@@ -68,3 +68,13 @@
.database :global(.advancedSearch .fieldDate input) {
margin: 0 5px 0 0;
}
+
+/* sanitize.css forms.css leaves form controls transparent; keep them on white. */
+.database :global(.formButton),
+.database :global(.fieldInputText),
+.database :global(.fieldSelect),
+.database :global(.fieldDate select),
+.database :global(.fieldDate input),
+.database :global(.listTable select) {
+ background-color: #ffffff;
+}
diff --git a/src/database/Database.tsx b/src/database/Database.tsx
index 97f1909..1582dd4 100644
--- a/src/database/Database.tsx
+++ b/src/database/Database.tsx
@@ -1,8 +1,7 @@
-import React from 'react';
-import { Helmet } from 'react-helmet';
-import { Route, RouteComponentProps, Switch } from 'react-router-dom';
+import { Helmet } from '@dr.pogodin/react-helmet';
+import { Route, Routes } from 'react-router';
import PageNotFound from '../common/lib/PageNotFound';
-import { MultiLang } from '../config';
+import type { MultiLang } from '../config';
import Functions from '../functions';
import styles from './Database.module.css';
import DatabaseAdvancedSearch from './DatabaseAdvancedSearch';
@@ -22,23 +21,28 @@ const Database = (props: Props) => {
return (