add ui components

This commit is contained in:
falsycat 2025-07-10 21:01:59 +09:00
parent c89478c1db
commit 5804a6cbff
7 changed files with 239 additions and 4 deletions

90
package-lock.json generated
View File

@ -10,8 +10,10 @@
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2", "@tauri-apps/api": "^2",
"@tauri-apps/plugin-opener": "^2", "@tauri-apps/plugin-opener": "^2",
"i18next": "^25.3.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1" "react-dom": "^18.3.1",
"react-i18next": "^15.6.0"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "^2", "@tauri-apps/cli": "^2",
@ -271,6 +273,15 @@
"@babel/core": "^7.0.0-0" "@babel/core": "^7.0.0-0"
} }
}, },
"node_modules/@babel/runtime": {
"version": "7.27.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
"integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.27.2", "version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
@ -1977,6 +1988,46 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"license": "MIT",
"dependencies": {
"void-elements": "3.1.0"
}
},
"node_modules/i18next": {
"version": "25.3.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.3.2.tgz",
"integrity": "sha512-JSnbZDxRVbphc5jiptxr3o2zocy5dEqpVm9qCGdJwRNO+9saUJS0/u4LnM/13C23fUEWxAylPqKU/NpMV/IjqA==",
"funding": [
{
"type": "individual",
"url": "https://locize.com"
},
{
"type": "individual",
"url": "https://locize.com/i18next.html"
},
{
"type": "individual",
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
}
],
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.27.6"
},
"peerDependencies": {
"typescript": "^5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/immutable": { "node_modules/immutable": {
"version": "5.1.3", "version": "5.1.3",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz",
@ -2218,6 +2269,32 @@
"react": "^18.3.1" "react": "^18.3.1"
} }
}, },
"node_modules/react-i18next": {
"version": "15.6.0",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.6.0.tgz",
"integrity": "sha512-W135dB0rDfiFmbMipC17nOhGdttO5mzH8BivY+2ybsQBbXvxWIwl3cmeH3T9d+YPBSJu/ouyJKFJTtkK7rJofw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.27.6",
"html-parse-stringify": "^3.0.1"
},
"peerDependencies": {
"i18next": ">= 23.2.3",
"react": ">= 16.8.0",
"typescript": "^5"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.17.0", "version": "0.17.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
@ -2367,7 +2444,7 @@
"version": "5.6.3", "version": "5.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@ -2483,6 +2560,15 @@
} }
} }
}, },
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",

View File

@ -12,8 +12,10 @@
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2", "@tauri-apps/api": "^2",
"@tauri-apps/plugin-opener": "^2", "@tauri-apps/plugin-opener": "^2",
"i18next": "^25.3.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1" "react-dom": "^18.3.1",
"react-i18next": "^15.6.0"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "^2", "@tauri-apps/cli": "^2",

21
src/i18n.ts Normal file
View File

@ -0,0 +1,21 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import en from './locales/en.json';
import jp from './locales/jp.json';
i18n
.use(initReactI18next)
.init({
resources: {
en: { translation: en },
jp: { translation: jp },
},
lng: 'jp', // 初期言語
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
});
export default i18n;

2
src/locales/en.json Normal file
View File

@ -0,0 +1,2 @@
{
}

33
src/locales/jp.json Normal file
View File

@ -0,0 +1,33 @@
{
"terms": {
"toshoGrowth": "東証グロース",
"toshoStandard": "東証スタンダード",
"toshoPrime": "東証プライム",
"stock": {
"price": "株価",
"volume": "時価総額"
}
},
"pages": {
"screening": {
"title": "銘柄スクリーニング",
"rerun": "再実行",
"universe": {
"title": "ユニバース",
"desc": "スクリーニング対象の銘柄の条件を設定してください",
"type": {
"listed": "全上場銘柄"
}
},
"evaluation": {
"title": "銘柄評価",
"desc": "銘柄一覧テーブルに表示する列を設定してください",
"columnName": "カラム名"
},
"filterOut": {
"title": "選別",
"desc": "銘柄の選別条件を設定してください"
}
}
}
}

View File

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import ReactDOM from "react-dom/client"; import ReactDOM from "react-dom/client";
import App from "./App"; import App from "./App";
import "./i18n";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode> <React.StrictMode>

View File

@ -1,6 +1,96 @@
import { ReactNode } from "react";
import { useTranslation } from "react-i18next";
function Screening() { function Screening() {
const {t} = useTranslation();
return ( return (
<h1>SCREENING</h1> <>
<h1>{t("pages.screening.title")}</h1>
<UniverseSpec/>
<EvaluationSpec/>
<FilterOutSpec/>
</>
); );
} }
export default Screening; export default Screening;
function UniverseSpec() {
const {t} = useTranslation();
return (
<FilterBox
title={t("pages.screening.universe.title")}
desc={t("pages.screening.universe.desc")}
>
<select>
<option>{t("pages.screening.universe.type.listed")}</option>
</select>
<label><input type="checkbox" />{t("terms.toshoGrowth")}</label>
<label><input type="checkbox" />{t("terms.toshoStandard")}</label>
<label><input type="checkbox" />{t("terms.toshoPrime")}</label>
</FilterBox>
);
}
function EvaluationSpec() {
const {t} = useTranslation();
return (
<FilterBox
title={t("pages.screening.evaluation.title")}
desc={t("pages.screening.evaluation.desc")}
>
<ol>
{
[...Array(3)].map((_,i)=>(
<li>
<input type="text" placeholder={t("pages.screening.evaluation.columnName")} />
=
<select>
<option>{t("terms.stock.volume")}</option>
<option>{t("terms.stock.price")}</option>
</select>
<a href="#">remove</a>
</li>
))
}
<li>
<a href="#">add</a>
</li>
</ol>
</FilterBox>
);
}
function FilterOutSpec() {
const {t} = useTranslation();
return (
<FilterBox
title={t("pages.screening.filterOut.title")}
desc={t("pages.screening.filterOut.desc")}
>
<textarea />
</FilterBox>
);
}
type FilterBoxProps = {
title: string,
desc: string,
children: ReactNode,
};
function FilterBox({title, desc, children}: FilterBoxProps) {
const {t} = useTranslation();
return (
<div>
<div>
<div>
<h2>{title}</h2>
<p>{desc}</p>
</div>
<div>
<a href="#">{t("pages.screening.rerun")}</a>
</div>
</div>
<div>{children}</div>
</div>
);
}