chore: update i18n for auth page

This commit is contained in:
Steven 2022-08-14 18:43:46 +08:00
parent 84a3548232
commit b596d04939
11 changed files with 190 additions and 159 deletions

View file

@ -20,10 +20,7 @@ const GitHubBadge: React.FC<Props> = () => {
<Icon.GitHub className="icon-img" />
Star
</div>
<div className="count-text">
{starCount || ""}
<span className="icon-text">🌟</span>
</div>
<div className="count-text">{starCount || ""}</div>
</a>
);
};

View file

@ -49,11 +49,15 @@ const MenuBtnsPopup: React.FC<Props> = (props: Props) => {
};
const handleSignOutBtnClick = async () => {
userService.doSignOut().catch(() => {
// do nth
});
locationService.replaceHistory("/signin");
window.location.reload();
userService
.doSignOut()
.then(() => {
locationService.replaceHistory("/auth");
window.location.reload();
})
.catch(() => {
// do nth
});
};
return (

105
web/src/less/auth.less Normal file
View file

@ -0,0 +1,105 @@
@import "./mixin.less";
.page-wrapper.auth {
@apply flex flex-row justify-center items-center w-full h-screen bg-white;
> .page-container {
@apply w-80 max-w-full h-full py-4 flex flex-col justify-start items-center;
> .auth-form-wrapper {
@apply w-full py-4 grow flex flex-col justify-center items-center;
> .page-header-container {
@apply flex flex-col justify-start items-start w-full mb-4;
> .title-container {
@apply w-full flex flex-row justify-between items-center;
> .title-text {
@apply text-2xl mb-2;
> .icon-text {
@apply text-4xl;
}
}
}
> .slogan-text {
@apply text-sm text-gray-700;
}
}
> .page-content-container {
@apply flex flex-col justify-start items-start w-full;
> .form-item-container {
@apply flex flex-col justify-start items-start relative w-full text-base mt-2;
> .normal-text {
@apply absolute top-3 left-3 px-1 leading-10 flex-shrink-0 text-base cursor-text text-gray-400 bg-transparent transition-all select-none;
&.not-null {
@apply text-sm top-0 z-10 leading-4 bg-white rounded;
}
}
&.input-form-container {
@apply py-2;
> input {
@apply w-full py-3 px-3 text-base shadow-inner rounded-lg border border-solid border-gray-400 hover:opacity-80;
}
}
}
&.requesting {
@apply opacity-80;
}
}
> .action-btns-container {
@apply flex flex-row justify-end items-center w-full mt-2;
> .btn {
@apply px-1 py-2 text-sm rounded hover:opacity-80;
&.signin-btn {
@apply bg-green-600 text-white px-3 shadow;
}
&.requesting {
@apply cursor-wait opacity-80;
}
}
}
> .tip-text {
@apply w-full inline-block float-right text-sm mt-4 text-gray-500 text-right whitespace-pre-wrap;
&.host-tip {
@apply bg-blue-500 text-white px-2 py-1 rounded;
}
}
}
> .footer-container {
@apply w-full flex flex-col justify-start items-center;
> .language-container {
@apply mt-2 w-full flex flex-row justify-center items-center text-sm text-gray-400;
> .locale-item {
@apply px-2 cursor-pointer;
&.active {
@apply text-blue-600 font-bold;
}
}
> .split-line {
@apply font-mono text-gray-400;
}
}
}
}
}

View file

@ -2,7 +2,7 @@
@apply h-7 flex flex-row justify-start items-center border rounded cursor-pointer hover:opacity-80;
> .github-icon {
@apply w-auto h-full px-2 border-r rounded-l flex flex-row justify-center items-center text-xs font-bold text-gray-800 bg-gray-100;
@apply w-auto h-full px-2 border-r rounded-l flex flex-row justify-center items-center text-xs text-gray-800 bg-gray-100;
> .icon-img {
@apply mr-1 w-4 h-4;
@ -11,24 +11,5 @@
> .count-text {
@apply w-auto h-full flex flex-row justify-center items-center px-3 text-xs font-bold text-gray-800;
> .icon-text {
@apply text-sm ml-1;
animation: 1.6s linear 0s infinite pulse;
}
}
}
@keyframes pulse {
0% {
transform: scale(0.95);
}
70% {
transform: scale(1.2);
}
100% {
transform: scale(0.95);
}
}

View file

@ -1,81 +0,0 @@
@import "./mixin.less";
.page-wrapper.signin {
@apply flex flex-row justify-center items-center w-full min-h-screen bg-white;
> .page-container {
@apply w-80 max-w-full py-4 -mt-16;
> .page-header-container {
@apply flex flex-col justify-start items-start w-full mb-4;
> .title-container {
@apply w-full flex flex-row justify-between items-center;
> .title-text {
@apply text-2xl mb-2;
> .icon-text {
@apply text-4xl;
}
}
}
> .slogan-text {
@apply text-sm text-gray-700;
}
}
> .page-content-container {
@apply flex flex-col justify-start items-start w-full;
> .form-item-container {
@apply flex flex-col justify-start items-start relative w-full text-base mt-2;
> .normal-text {
@apply absolute top-3 left-3 px-1 leading-10 flex-shrink-0 text-base cursor-text text-gray-400 bg-transparent transition-all select-none;
&.not-null {
@apply text-sm top-0 z-10 leading-4 bg-white rounded;
}
}
&.input-form-container {
@apply py-2;
> input {
@apply w-full py-3 px-3 text-base shadow-inner rounded-lg border border-solid border-gray-400 hover:opacity-80;
}
}
}
&.requesting {
@apply opacity-80;
}
}
> .action-btns-container {
@apply flex flex-row justify-end items-center w-full mt-2;
> .btn {
@apply px-1 py-2 text-sm rounded hover:opacity-80;
&.signin-btn {
@apply bg-green-600 text-white px-3 shadow;
}
&.requesting {
@apply cursor-wait opacity-80;
}
}
}
> .tip-text {
@apply w-auto inline-block float-right text-sm mt-4 text-gray-500 text-right whitespace-pre-wrap;
&.host-tip {
@apply bg-blue-500 text-white px-2 py-1 rounded;
}
}
}
}

View file

@ -4,5 +4,11 @@
"email": "Email",
"password": "Password",
"sign-in": "Sign in"
},
"slogan": "An open source, self-hosted knowledge base that works with a SQLite db file.",
"auth": {
"signup-as-host": "Sign up as Host",
"host-tip": "You are registering as the Site Host.",
"not-host-tip": "If you don't have an account, please contact the site host."
}
}

View file

@ -4,5 +4,11 @@
"email": "邮箱",
"password": "密码",
"sign-in": "登录"
},
"slogan": "一个开源的、支持私有化部署的碎片化知识卡片管理工具。",
"auth": {
"signup-as-host": "注册为 Host",
"host-tip": "你正在注册为 Host 用户账号。",
"not-host-tip": "如果你没有账号,请联系站点 Host"
}
}

View file

@ -3,10 +3,10 @@ import * as api from "../helpers/api";
import { validate, ValidatorConfig } from "../helpers/validator";
import useI18n from "../hooks/useI18n";
import useLoading from "../hooks/useLoading";
import { locationService, userService } from "../services";
import { globalService, locationService, userService } from "../services";
import toastHelper from "../components/Toast";
import GitHubBadge from "../components/GitHubBadge";
import "../less/signin.less";
import "../less/auth.less";
interface Props {}
@ -17,8 +17,8 @@ const validateConfig: ValidatorConfig = {
noChinese: true,
};
const Signin: React.FC<Props> = () => {
const { t } = useI18n();
const Auth: React.FC<Props> = () => {
const { t, locale } = useI18n();
const pageLoadingState = useLoading(true);
const [siteHost, setSiteHost] = useState<User>();
const [email, setEmail] = useState("");
@ -113,55 +113,68 @@ const Signin: React.FC<Props> = () => {
actionBtnLoadingState.setFinish();
};
const handleLocaleItemClick = (locale: Locale) => {
globalService.setLocale(locale);
};
return (
<div className="page-wrapper signin">
<div className="page-wrapper auth">
<div className="page-container">
<div className="page-header-container">
<div className="title-container">
<p className="title-text">
<span className="icon-text"></span> Memos
</p>
<GitHubBadge />
<div className="auth-form-wrapper">
<div className="page-header-container">
<div className="title-container">
<p className="title-text">
<span className="icon-text"></span> Memos
</p>
<GitHubBadge />
</div>
<p className="slogan-text">{t("slogan")}</p>
</div>
<p className="slogan-text">
An <i>open source</i>, <i>self-hosted</i> knowledge base that works with a SQLite db file.
<div className={`page-content-container ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}>
<div className="form-item-container input-form-container">
<span className={`normal-text ${email ? "not-null" : ""}`}>{t("common.email")}</span>
<input type="email" value={email} onChange={handleEmailInputChanged} />
</div>
<div className="form-item-container input-form-container">
<span className={`normal-text ${password ? "not-null" : ""}`}>{t("common.password")}</span>
<input type="password" value={password} onChange={handlePasswordInputChanged} />
</div>
</div>
<div className="action-btns-container">
{siteHost || pageLoadingState.isLoading ? (
<button
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
onClick={() => handleSigninBtnsClick()}
>
{t("common.sign-in")}
</button>
) : (
<button
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
onClick={() => handleSignUpAsHostBtnsClick()}
>
{t("auth.signup-as-host")}
</button>
)}
</div>
<p className={`tip-text ${siteHost || pageLoadingState.isLoading ? "" : "host-tip"}`}>
{siteHost || pageLoadingState.isLoading ? t("auth.not-host-tip") : t("auth.host-tip")}
</p>
</div>
<div className={`page-content-container ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}>
<div className="form-item-container input-form-container">
<span className={`normal-text ${email ? "not-null" : ""}`}>{t("common.email")}</span>
<input type="email" value={email} onChange={handleEmailInputChanged} />
</div>
<div className="form-item-container input-form-container">
<span className={`normal-text ${password ? "not-null" : ""}`}>{t("common.password")}</span>
<input type="password" value={password} onChange={handlePasswordInputChanged} />
<div className="footer-container">
<div className="language-container">
<span className={`locale-item ${locale === "en" ? "active" : ""}`} onClick={() => handleLocaleItemClick("en")}>
English
</span>
<span className="split-line">/</span>
<span className={`locale-item ${locale === "zh" ? "active" : ""}`} onClick={() => handleLocaleItemClick("zh")}>
</span>
</div>
</div>
<div className="action-btns-container">
{siteHost || pageLoadingState.isLoading ? (
<button
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
onClick={() => handleSigninBtnsClick()}
>
{t("common.sign-in")}
</button>
) : (
<button
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
onClick={() => handleSignUpAsHostBtnsClick()}
>
Sign up as Host
</button>
)}
</div>
<p className={`tip-text ${siteHost || pageLoadingState.isLoading ? "" : "host-tip"}`}>
{siteHost || pageLoadingState.isLoading
? "If you don't have an account, please\ncontact the site host."
: "You are registering as the Site Host."}
</p>
</div>
</div>
);
};
export default Signin;
export default Auth;

View file

@ -23,7 +23,7 @@ function Home() {
.finally(async () => {
const { host, owner, user } = userService.getState();
if (!host) {
locationService.replaceHistory("/signin");
locationService.replaceHistory("/auth");
return;
}
@ -61,7 +61,7 @@ function Home() {
<span className="icon">🏠</span> Back to Home
</button>
) : (
<button className="btn" onClick={() => (window.location.href = "/signin")}>
<button className="btn" onClick={() => (window.location.href = "/auth")}>
<span className="icon">👉</span> Sign in
</button>
)}

View file

@ -1,8 +1,8 @@
import Home from "../pages/Home";
import Signin from "../pages/Signin";
import Auth from "../pages/Auth";
const appRouter = {
"/signin": <Signin />,
"/auth": <Auth />,
"*": <Home />,
};

View file

@ -21,7 +21,7 @@ interface State {
const getValidPathname = (pathname: string): string => {
const userPageUrlRegex = /^\/u\/\d+.*/;
if (["/", "/signin"].includes(pathname) || userPageUrlRegex.test(pathname)) {
if (["/", "/auth"].includes(pathname) || userPageUrlRegex.test(pathname)) {
return pathname;
} else {
return "/";