Merged PR 51: タスク 1468: 部品component作成(ヘッダー・フッター)
## 概要 [Task: 1468](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_sprints/taskboard/OMDSDictation%20%E3%83%81%E3%83%BC%E3%83%A0/OMDSDictation/%E3%82%B9%E3%83%97%E3%83%AA%E3%83%B3%E3%83%88%204-2?workitem=1468) - ヘッダーcomponentを作成 - ログイン前とログイン後でヘッダーが異なるので各ページに配置するようにした - 呼び出すcomponentは一つとして作成し、内部でヘッダーを切り替えるようにした - フッターcomponentを作成 - ログイン前とログイン後でページのデザインが異なるのでヘッダー同様、各ページに配置することにした ## レビューポイント - ヘッダーの作成方法に問題はないか ## UIの変更 - https://ndstokyo.sharepoint.com/:f:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task1468?csf=1&web=1&e=K2tFjK ## 動作確認状況 - 型チェック - ローカルで動作確認 ## 補足
This commit is contained in:
parent
dfd9abc1c3
commit
b4cd0208e6
@ -13,6 +13,7 @@ import "./styles/GlobalStyle.css";
|
||||
const App = (): JSX.Element => {
|
||||
const dispatch = useDispatch();
|
||||
const { instance } = useMsal();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [t, i18n] = useTranslation();
|
||||
const pca = new PublicClientApplication(msalConfig);
|
||||
useEffect(() => {
|
||||
|
||||
@ -11,10 +11,31 @@ const AppRouter: React.FC = () => (
|
||||
<Routes>
|
||||
<Route path="/" element={<TopPage />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/AuthError" element={<AuthErrorPage />} />
|
||||
<Route path="/authError" element={<AuthErrorPage />} />
|
||||
<Route path="/signup" element={<SignupPage completeTo="/" />} />
|
||||
<Route
|
||||
path="/XXX"
|
||||
path="/xxx"
|
||||
element={<RouteAuthGuard component={<SamplePage />} />}
|
||||
/>
|
||||
{/* XXX ヘッダーの挙動確認のため仮のページを作成 */}
|
||||
<Route
|
||||
path="/account"
|
||||
element={<RouteAuthGuard component={<SamplePage />} />}
|
||||
/>
|
||||
<Route
|
||||
path="/user"
|
||||
element={<RouteAuthGuard component={<SamplePage />} />}
|
||||
/>
|
||||
<Route
|
||||
path="/dictations"
|
||||
element={<RouteAuthGuard component={<SamplePage />} />}
|
||||
/>
|
||||
<Route
|
||||
path="/license"
|
||||
element={<RouteAuthGuard component={<SamplePage />} />}
|
||||
/>
|
||||
<Route
|
||||
path="/workflow"
|
||||
element={<RouteAuthGuard component={<SamplePage />} />}
|
||||
/>
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
|
||||
10
dictation_client/src/components/footer/footer.module.scss
Normal file
10
dictation_client/src/components/footer/footer.module.scss
Normal file
@ -0,0 +1,10 @@
|
||||
.footer {
|
||||
grid-area: footer;
|
||||
padding: 0.6rem 0;
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
line-height: 1.45;
|
||||
letter-spacing: 0.4px;
|
||||
font-weight: normal;
|
||||
color: #999999;
|
||||
}
|
||||
4
dictation_client/src/components/footer/footer.module.scss.d.ts
vendored
Normal file
4
dictation_client/src/components/footer/footer.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare const classNames: {
|
||||
readonly footer: "footer";
|
||||
};
|
||||
export = classNames;
|
||||
10
dictation_client/src/components/footer/index.tsx
Normal file
10
dictation_client/src/components/footer/index.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
import styles from "./footer.module.scss";
|
||||
|
||||
const Footer: React.FC = () => (
|
||||
<footer className={`${styles.footer}`}>
|
||||
<div>© OM Digital Solutions 2023</div>
|
||||
</footer>
|
||||
);
|
||||
|
||||
export default Footer;
|
||||
12
dictation_client/src/components/header/constants.ts
Normal file
12
dictation_client/src/components/header/constants.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { HeaderMenus, LoginedPaths } from "./types";
|
||||
|
||||
export const HEADER_MENUS: { label: HeaderMenus; path: LoginedPaths }[] = [
|
||||
{ label: "Account", path: "/account" },
|
||||
{ label: "Dictations", path: "/dictations" },
|
||||
{ label: "License", path: "/license" },
|
||||
{ label: "User", path: "/user" },
|
||||
{ label: "Workflow", path: "/workflow" },
|
||||
{ label: "XXX", path: "/xxx" }, // XXX 仮のタブ
|
||||
];
|
||||
|
||||
export const HEADER_NAME = "ODMS Cloud";
|
||||
47
dictation_client/src/components/header/header.module.scss
Normal file
47
dictation_client/src/components/header/header.module.scss
Normal file
@ -0,0 +1,47 @@
|
||||
.header {
|
||||
grid-area: header;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 0 3px #282828;
|
||||
background: linear-gradient(#ffffff, #ffffff 70%, #f0f0f0 100%);
|
||||
z-index: 4;
|
||||
}
|
||||
.headerLogo {
|
||||
margin: 1.8rem 2rem 1rem;
|
||||
font-size: 1.71rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
.headerLogo img {
|
||||
width: 198px;
|
||||
}
|
||||
.headerSub {
|
||||
margin: 1.8rem 2rem 1rem;
|
||||
font-size: 1.2rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: normal;
|
||||
font-weight: 600;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1280px) {
|
||||
.header.home {
|
||||
display: block;
|
||||
padding-top: 30vh;
|
||||
padding-left: 40%;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.header.home .headerSub {
|
||||
font-size: 1.4rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
7
dictation_client/src/components/header/header.module.scss.d.ts
vendored
Normal file
7
dictation_client/src/components/header/header.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
declare const classNames: {
|
||||
readonly header: "header";
|
||||
readonly headerLogo: "headerLogo";
|
||||
readonly headerSub: "headerSub";
|
||||
readonly home: "home";
|
||||
};
|
||||
export = classNames;
|
||||
25
dictation_client/src/components/header/index.tsx
Normal file
25
dictation_client/src/components/header/index.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import LoginedHeader from "./loginedHeader";
|
||||
import NotLoginHeader from "./notLoginHeader";
|
||||
import { isLoginPaths } from "./utils";
|
||||
|
||||
interface HeaderProps {
|
||||
userName?: string;
|
||||
// userRole: string; ログインユーザーのロールに応じてタブの活性非活性に使用する想定
|
||||
}
|
||||
// ヘッダー切り替え用のcomponent
|
||||
const Header: React.FC<HeaderProps> = (props) => {
|
||||
const { userName } = props;
|
||||
const location = useLocation();
|
||||
return getHeader(location.pathname, userName);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
||||
const getHeader = (path: string, userName?: string) => {
|
||||
if (isLoginPaths(path) && userName) {
|
||||
return <LoginedHeader name={userName} activePath={path} />;
|
||||
}
|
||||
return <NotLoginHeader isMobile={path === "/"} />;
|
||||
};
|
||||
@ -0,0 +1,87 @@
|
||||
.header {
|
||||
grid-area: header;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 0 3px #282828;
|
||||
background: linear-gradient(#ffffff, #ffffff 70%, #f0f0f0 100%);
|
||||
z-index: 4;
|
||||
}
|
||||
.headerLogo {
|
||||
margin: 1.2rem 2rem 1rem;
|
||||
font-size: 1.71rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
.headerLogo img {
|
||||
width: 198px;
|
||||
}
|
||||
.headerSub {
|
||||
margin: 1.4rem 2rem 1rem;
|
||||
font-size: 1.2rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: normal;
|
||||
font-weight: 600;
|
||||
text-align: right;
|
||||
}
|
||||
.headerMenu {
|
||||
width: 100%;
|
||||
}
|
||||
.headerMenu ul {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
.headerMenu ul li {
|
||||
font-size: 1rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: normal;
|
||||
border-left: 1px #e6e6e6 solid;
|
||||
}
|
||||
.headerMenu ul li a {
|
||||
display: block;
|
||||
padding: 0 2rem;
|
||||
color: #333333;
|
||||
text-decoration: none;
|
||||
-moz-transition: all 0.3s ease-out;
|
||||
-ms-transition: all 0.3s ease-out;
|
||||
-webkit-transition: all 0.3s ease-out;
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
.headerMenu ul li a:hover {
|
||||
background: #fafafa;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.headerMenu ul li a.isActive {
|
||||
font-weight: 600;
|
||||
pointer-events: none;
|
||||
position: relative;
|
||||
}
|
||||
.headerMenu ul li a.isActive::after {
|
||||
content: "";
|
||||
border-right: 0.6rem transparent solid;
|
||||
border-bottom: 0.6rem #282828 solid;
|
||||
border-left: 0.6rem transparent solid;
|
||||
position: absolute;
|
||||
bottom: -4px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.accountInfo {
|
||||
position: absolute;
|
||||
right: 2rem;
|
||||
bottom: 0.3rem;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.6rem;
|
||||
letter-spacing: 0.04rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
.accountIcon {
|
||||
width: 1.4rem;
|
||||
vertical-align: top;
|
||||
}
|
||||
10
dictation_client/src/components/header/loginedHeader.module.scss.d.ts
vendored
Normal file
10
dictation_client/src/components/header/loginedHeader.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
declare const classNames: {
|
||||
readonly header: "header";
|
||||
readonly headerLogo: "headerLogo";
|
||||
readonly headerSub: "headerSub";
|
||||
readonly headerMenu: "headerMenu";
|
||||
readonly isActive: "isActive";
|
||||
readonly accountInfo: "accountInfo";
|
||||
readonly accountIcon: "accountIcon";
|
||||
};
|
||||
export = classNames;
|
||||
51
dictation_client/src/components/header/loginedHeader.tsx
Normal file
51
dictation_client/src/components/header/loginedHeader.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import React from "react";
|
||||
import styles from "./loginedHeader.module.scss";
|
||||
|
||||
import logo from "../../assets/images/OMS_logo_black.svg";
|
||||
import ac from "../../assets/images/account_circle.svg";
|
||||
import { LoginedPaths } from "./types";
|
||||
import { HEADER_MENUS, HEADER_NAME } from "./constants";
|
||||
|
||||
interface HeaderProps {
|
||||
// userRole: "user" | "partner"; ログインユーザーのロールに応じてタブの活性非活性に使用する想定
|
||||
name: string;
|
||||
activePath: LoginedPaths;
|
||||
}
|
||||
|
||||
// ログイン後のヘッダー
|
||||
const LoginedHeader: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
const { name, activePath } = props;
|
||||
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<div className={styles.headerLogo}>
|
||||
<img src={logo} alt="OM System" />
|
||||
</div>
|
||||
<div className={styles.headerSub}>{HEADER_NAME}</div>
|
||||
<div className={styles.headerMenu}>
|
||||
<ul>
|
||||
{HEADER_MENUS.map((x) => (
|
||||
<li key={x.label}>
|
||||
<a
|
||||
href={x.path}
|
||||
className={
|
||||
activePath.toUpperCase() === x.path.toUpperCase()
|
||||
? styles.isActive
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{x.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<p className={styles.accountInfo}>
|
||||
<img src={ac} alt="" className={styles.accountIcon} />
|
||||
|
||||
<span>{name}</span>
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
export default LoginedHeader;
|
||||
27
dictation_client/src/components/header/notLoginHeader.tsx
Normal file
27
dictation_client/src/components/header/notLoginHeader.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import styles from "./header.module.scss";
|
||||
|
||||
import logo from "../../assets/images/OMS_logo_black.svg";
|
||||
import { HEADER_NAME } from "./constants";
|
||||
|
||||
interface NotLoginHeaderProps {
|
||||
isMobile?: boolean;
|
||||
}
|
||||
// ログインしていない時のヘッダー
|
||||
const NotLoginHeader: React.FC<NotLoginHeaderProps> = (
|
||||
props: NotLoginHeaderProps
|
||||
) => {
|
||||
const { isMobile } = props;
|
||||
return (
|
||||
<header className={`${styles.header} ${isMobile && styles.home}`}>
|
||||
<div className={`${styles.headerLogo}`}>
|
||||
<img src={logo} alt="OM System" />
|
||||
</div>
|
||||
<p className={`${styles.headerSub}`}>{HEADER_NAME}</p>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
NotLoginHeader.defaultProps = {
|
||||
isMobile: false,
|
||||
};
|
||||
export default NotLoginHeader;
|
||||
20
dictation_client/src/components/header/types.ts
Normal file
20
dictation_client/src/components/header/types.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// ページパス
|
||||
export type Paths = LoginedPaths | "/" | "/signup" | "login";
|
||||
|
||||
// ログイン後のヘッダータブ
|
||||
export type HeaderMenus =
|
||||
| "Account"
|
||||
| "User"
|
||||
| "License"
|
||||
| "Dictations"
|
||||
| "Workflow"
|
||||
| "XXX";
|
||||
|
||||
// ログイン後に遷移しうるパス
|
||||
export type LoginedPaths =
|
||||
| "/account"
|
||||
| "/user"
|
||||
| "/license"
|
||||
| "/dictations"
|
||||
| "/workflow"
|
||||
| "/xxx";
|
||||
21
dictation_client/src/components/header/utils.ts
Normal file
21
dictation_client/src/components/header/utils.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { LoginedPaths } from "./types";
|
||||
|
||||
// ログイン後のパスかどうか判定
|
||||
export const isLoginPaths = (d: string): d is LoginedPaths => {
|
||||
// caseに入力補完で取りうるリテラルしか出なくする
|
||||
const type = d as LoginedPaths;
|
||||
switch (type) {
|
||||
case "/account":
|
||||
case "/user":
|
||||
case "/license":
|
||||
case "/dictations":
|
||||
case "/workflow":
|
||||
case "/xxx":
|
||||
return true;
|
||||
default: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const _: never = type;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1,9 +1,7 @@
|
||||
import { UpdateTokenTimer } from "components/auth/updateTokenTimer";
|
||||
import React from "react";
|
||||
|
||||
export const AuthErrorPage = (): JSX.Element => (
|
||||
<div>
|
||||
<UpdateTokenTimer />
|
||||
<p>ログインに失敗しました</p>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { InteractionStatus, SilentRequest } from "@azure/msal-browser";
|
||||
import { useIsAuthenticated, useMsal } from "@azure/msal-react";
|
||||
import { AppDispatch } from "app/store";
|
||||
import Footer from "components/footer";
|
||||
import Header from "components/header";
|
||||
import { loginAsync } from "features/login";
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
@ -26,7 +28,7 @@ const LoginPage: React.FC = (): JSX.Element => {
|
||||
});
|
||||
}
|
||||
if (meta.requestStatus === "fulfilled") {
|
||||
navigate("/XXX");
|
||||
navigate("/xxx");
|
||||
}
|
||||
}, [accounts, dispatch, instance, navigate]);
|
||||
|
||||
@ -45,7 +47,13 @@ const LoginPage: React.FC = (): JSX.Element => {
|
||||
navigate,
|
||||
]);
|
||||
|
||||
return <h3>loading ...</h3>;
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<h3>loading ...</h3>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
|
||||
@ -1,19 +1,24 @@
|
||||
import { useMsal } from "@azure/msal-react";
|
||||
import { AppDispatch } from "app/store";
|
||||
import { UpdateTokenTimer } from "components/auth/updateTokenTimer";
|
||||
import Footer from "components/footer";
|
||||
import Header from "components/header";
|
||||
import { clearToken } from "features/auth";
|
||||
import React from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import styles from "./sample.module.scss";
|
||||
|
||||
const SamplePage: React.FC = (): JSX.Element => {
|
||||
const { instance } = useMsal();
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.wrap}>
|
||||
<Header userName="XXXXXX" />
|
||||
<UpdateTokenTimer />
|
||||
<h1>hello world!!</h1>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.button}
|
||||
onClick={() => {
|
||||
instance.logout({ postLogoutRedirectUri: "/" });
|
||||
dispatch(clearToken());
|
||||
@ -22,6 +27,8 @@ const SamplePage: React.FC = (): JSX.Element => {
|
||||
sign out
|
||||
</button>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
21
dictation_client/src/pages/SamplePage/sample.module.scss
Normal file
21
dictation_client/src/pages/SamplePage/sample.module.scss
Normal file
@ -0,0 +1,21 @@
|
||||
.wrap {
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas: "header" "main" "footer";
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: block;
|
||||
padding: 12px 0;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
background: #005eb8;
|
||||
border: 1px #005eb8 solid;
|
||||
margin-left: 100px;
|
||||
cursor: pointer;
|
||||
:hover {
|
||||
background: rgba(0, 94, 184, 0.7);
|
||||
}
|
||||
}
|
||||
5
dictation_client/src/pages/SamplePage/sample.module.scss.d.ts
vendored
Normal file
5
dictation_client/src/pages/SamplePage/sample.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare const classNames: {
|
||||
readonly wrap: "wrap";
|
||||
readonly button: "button";
|
||||
};
|
||||
export = classNames;
|
||||
@ -1,3 +1,5 @@
|
||||
import Footer from "components/footer";
|
||||
import Header from "components/header";
|
||||
import { selectPageState } from "features/signup/selectors";
|
||||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
@ -9,7 +11,13 @@ const SignupPage: React.FC<{ completeTo: string }> = ({
|
||||
}): JSX.Element => {
|
||||
const state = useSelector(selectPageState);
|
||||
|
||||
return getComponent(state, completeTo);
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
{getComponent(state, completeTo)}
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// 現在のサインアップ画面の状態に応じて表示Componentを出し分ける
|
||||
|
||||
@ -6,39 +6,6 @@
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 0 3px #282828;
|
||||
background: linear-gradient(#ffffff, #ffffff 70%, #f0f0f0 100%);
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.headerLogo {
|
||||
margin: 1.8rem 2rem 1rem;
|
||||
font-size: 1.71rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.headerLogo img {
|
||||
width: 198px;
|
||||
}
|
||||
|
||||
.headerSub {
|
||||
margin: 1.8rem 2rem 1rem;
|
||||
font-size: 1.2rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: normal;
|
||||
font-weight: 600;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.main {
|
||||
grid-area: main;
|
||||
}
|
||||
@ -171,24 +138,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1280px) {
|
||||
.header.home {
|
||||
display: block;
|
||||
padding-top: 30vh;
|
||||
padding-left: 40%;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.header.home .headerSub {
|
||||
font-size: 1.4rem;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.pgHome > div {
|
||||
width: 400px;
|
||||
margin: 15vh auto 0;
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
declare const classNames: {
|
||||
readonly wrap: "wrap";
|
||||
readonly header: "header";
|
||||
readonly headerLogo: "headerLogo";
|
||||
readonly headerSub: "headerSub";
|
||||
readonly main: "main";
|
||||
readonly mainSmall: "mainSmall";
|
||||
readonly footer: "footer";
|
||||
|
||||
@ -3,8 +3,9 @@ import { loginRequest } from "common/msalConfig";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTranslationID } from "translation";
|
||||
import Header from "components/header";
|
||||
import Footer from "components/footer";
|
||||
import { LANGUAGE_LIST } from "../../features/top/constants";
|
||||
import logo from "../../assets/images/OMS_logo_black.svg";
|
||||
import arrow_forward from "../../assets/images/arrow_forward.svg";
|
||||
import arrow_forward_bule from "../../assets/images/arrow_forward_blue.svg";
|
||||
import styles from "./TopPage.module.scss";
|
||||
@ -16,14 +17,7 @@ const TopPage: React.FC = (): JSX.Element => {
|
||||
|
||||
return (
|
||||
<div className={`${styles.wrap} ${styles.home}`}>
|
||||
<header className={`${styles.header} ${styles.home}`}>
|
||||
<div className={`${styles.headerLogo}`}>
|
||||
<img src={logo} alt="OM System" />
|
||||
</div>
|
||||
<p className={`${styles.headerSub}`}>
|
||||
{t(getTranslationID("common.label.headerTitle"))}
|
||||
</p>
|
||||
</header>
|
||||
<Header />
|
||||
|
||||
<main className={`${styles.main} ${styles.home}`}>
|
||||
<section className={`${styles.pgHome}`}>
|
||||
@ -87,10 +81,7 @@ const TopPage: React.FC = (): JSX.Element => {
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer className={`${styles.footer}`}>
|
||||
<div>© {t(getTranslationID("common.label.copyRight"))}</div>
|
||||
</footer>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
21
dictation_client/src/styles/app.module.scss
Normal file
21
dictation_client/src/styles/app.module.scss
Normal file
@ -0,0 +1,21 @@
|
||||
.wrap {
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas: "header" "main" "footer";
|
||||
min-height: 100vh;
|
||||
}
|
||||
.wrap.home {
|
||||
background: url("../assets/images/top-bg04.png") no-repeat bottom center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1280px) {
|
||||
.wrap.home {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr auto;
|
||||
grid-template-columns: 45% 1fr;
|
||||
grid-template-areas: "header main" "footer footer";
|
||||
min-height: 100vh;
|
||||
}
|
||||
}
|
||||
5
dictation_client/src/styles/app.module.scss.d.ts
vendored
Normal file
5
dictation_client/src/styles/app.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare const classNames: {
|
||||
readonly wrap: "wrap";
|
||||
readonly home: "home";
|
||||
};
|
||||
export = classNames;
|
||||
Loading…
x
Reference in New Issue
Block a user