Skip to content

feat(auth): Add linkComponent/labels props to auth forms, i18n support, widescreen layout#990

Merged
hotlong merged 5 commits into
mainfrom
copilot/optimize-login-page-visuals
Mar 3, 2026
Merged

feat(auth): Add linkComponent/labels props to auth forms, i18n support, widescreen layout#990
hotlong merged 5 commits into
mainfrom
copilot/optimize-login-page-visuals

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 3, 2026

Auth page links (Sign up, Forgot password, Sign in) use raw <a> tags that ignore React Router's basename, so deploying under /console prefix produces broken links. All form text is hardcoded English with no i18n path. Widescreen layout is a bare centered 350px form.

linkComponent prop — fixes prefix routing

Auth forms accept an optional linkComponent prop (React.ComponentType<AuthLinkComponentProps>) defaulting to <a>. Console pages now pass a React Router <Link> wrapper, which respects BrowserRouter basename automatically:

import { Link } from 'react-router-dom';
import { LoginForm, type AuthLinkComponentProps } from '@object-ui/auth';

const RouterLink = ({ href, className, children }: AuthLinkComponentProps) => (
  <Link to={href} className={className}>{children}</Link>
);

<LoginForm linkComponent={RouterLink} registerUrl="/register" forgotPasswordUrl="/forgot-password" />

labels prop — i18n support

Each form accepts a partial labels object to override all user-facing strings. Console pages wire this to useObjectTranslation():

<LoginForm labels={{ emailLabel: t('auth.login.emailLabel'), submitButton: t('auth.login.submitButton') }} />

i18n locale additions

  • Added auth.login.*, auth.register.*, auth.forgotPassword.* keys to all 10 locale files (en, zh, ja, ko, de, fr, es, pt, ru, ar)
  • successDescription uses {{email}} placeholder for proper sentence structure across languages

Widescreen layout

  • New AuthPageLayout component: split-panel design (branding left / form right on lg+, full-width form on mobile)
  • Applied to LoginPage, RegisterPage, ForgotPasswordPage
  • Form width bumped from sm:w-[350px]sm:w-[380px]

Exports

  • AuthLinkComponentProps, LoginFormLabels, RegisterFormLabels, ForgotPasswordFormLabels exported from @object-ui/auth
Original prompt

This section details on the original issue you should resolve

<issue_title>登录页面优化及 /console 前缀配置导致 API 路径错误(宽屏模式、404 问题)</issue_title>
<issue_description>参考其他主流企业管理平台,整体优化登录页面宽屏模式下的视觉体验。当前宽屏状态下页面美观性不足。

另,配置 /console 前缀时,相关链接注册,登录,忘记密码等未自动加上前缀。

请优化前端路由逻辑,以能正确拼接 API 请求路径并支持多前缀场景。

附错误截图:
登录页面宽屏与报错

需求:

  1. 登录页视觉及布局参考主流管理平台整体优化(如airtable,salesforce,power apps等)。
  2. 支持 /console 等前缀情况下,API 请求能自动拼接对应前缀。
  3. 所有登录页面缺少国际化翻译。
  4. 检查注册(Sign up)、找回密码等同样受影响的链接路径。</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectui Ready Ready Preview, Comment Mar 3, 2026 6:47am
objectui-demo Error Error Mar 3, 2026 6:47am
objectui-storybook Ready Ready Preview, Comment Mar 3, 2026 6:47am

Request Review

Copilot AI and others added 4 commits March 3, 2026 05:11
Add translated auth section (login, register, forgotPassword) to
ja, ko, de, fr, es, pt, ru, and ar locale files, positioned before
the errors section to match en.ts and zh.ts structure.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…h i18n to all locales, improve console auth pages with widescreen layout

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…upport

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Optimize login page visual experience and API path configuration feat(auth): Add linkComponent/labels props to auth forms, i18n support, widescreen layout Mar 3, 2026
@hotlong hotlong marked this pull request as ready for review March 3, 2026 05:36
Copilot AI review requested due to automatic review settings March 3, 2026 05:36
@hotlong hotlong merged commit a00446f into main Mar 3, 2026
3 of 4 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds router-aware auth page links and i18n-ready auth form copy, and introduces a shared widescreen auth layout for the console.

Changes:

  • Add linkComponent support to auth forms so navigation works correctly under React Router basename (e.g. /console).
  • Add labels override objects to auth forms and wire console auth pages to useObjectTranslation() with new auth.* locale keys.
  • Introduce AuthPageLayout split-panel layout and apply it to console auth pages.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/i18n/src/locales/en.ts Adds auth.login/register/forgotPassword.* translation keys (source language).
packages/i18n/src/locales/zh.ts Adds Chinese auth translations including {{email}} placeholder usage.
packages/i18n/src/locales/ja.ts Adds Japanese auth translations.
packages/i18n/src/locales/ko.ts Adds Korean auth translations.
packages/i18n/src/locales/de.ts Adds German auth translations.
packages/i18n/src/locales/fr.ts Adds French auth translations.
packages/i18n/src/locales/es.ts Adds Spanish auth translations.
packages/i18n/src/locales/pt.ts Adds Portuguese auth translations.
packages/i18n/src/locales/ru.ts Adds Russian auth translations.
packages/i18n/src/locales/ar.ts Adds Arabic auth translations.
packages/auth/src/types.ts Introduces AuthLinkComponentProps for custom link rendering.
packages/auth/src/index.ts Exports new label types and AuthLinkComponentProps from @object-ui/auth.
packages/auth/src/LoginForm.tsx Adds linkComponent + labels props and replaces hardcoded strings with label defaults.
packages/auth/src/RegisterForm.tsx Adds linkComponent + labels props and replaces hardcoded strings with label defaults.
packages/auth/src/ForgotPasswordForm.tsx Adds linkComponent + labels props and updates success message rendering.
packages/auth/src/tests/LoginForm.test.tsx Tests custom linkComponent usage and label overrides.
packages/auth/src/tests/RegisterForm.test.tsx Tests custom linkComponent usage and label overrides.
packages/auth/src/tests/ForgotPasswordForm.test.tsx Tests custom linkComponent usage and label overrides.
apps/console/src/components/AuthPageLayout.tsx Adds shared split-panel auth layout for widescreen.
apps/console/src/pages/LoginPage.tsx Uses AuthPageLayout, passes router Link wrapper + i18n labels into LoginForm.
apps/console/src/pages/RegisterPage.tsx Uses AuthPageLayout, passes router Link wrapper + i18n labels into RegisterForm.
apps/console/src/pages/ForgotPasswordPage.tsx Uses AuthPageLayout, passes router Link wrapper + i18n labels into ForgotPasswordForm.

Comment on lines +101 to +103
const successMsg = l.successDescription.includes('{{email}}')
? l.successDescription.replace('{{email}}', email)
: `${l.successDescription} ${email}`;
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the submitted state, successDescription is treated as a string template and then conditionally appended with the email. This can produce duplicated email (if callers pass an already-interpolated string) and only replaces the first {{email}} occurrence. Consider making this deterministic by always replacing all occurrences of the placeholder (e.g. global replace), and avoid the fallback append that can duplicate content—either require {{email}} in the template or render the email separately in JSX.

Suggested change
const successMsg = l.successDescription.includes('{{email}}')
? l.successDescription.replace('{{email}}', email)
: `${l.successDescription} ${email}`;
const successMsg = l.successDescription.replace(/{{email}}/g, email);

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +35
<span className="text-2xl font-bold">ObjectStack</span>
</div>
<h2 className="text-3xl font-bold leading-tight">
Build powerful business applications, faster.
</h2>
<p className="text-lg opacity-90">
The universal platform for enterprise data management, workflows, and analytics.
</p>
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AuthPageLayout introduces new user-facing strings (tagline/description) that are not wired to the console i18n system, so auth pages are still partially non-translatable. Consider passing these strings in as props from the pages (using useObjectTranslation()), or adding auth.layout.* keys to the locale files and translating here.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +32
>
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
</svg>
<span className="text-2xl font-bold">ObjectStack</span>
</div>
<h2 className="text-3xl font-bold leading-tight">
Build powerful business applications, faster.
</h2>
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The branding panel uses an unlabelled SVG and a semantic <h2> that appears before the form’s <h1> in DOM order. For accessibility, mark decorative SVGs as aria-hidden (or provide an accessible name), and avoid heading-level jumps by using non-heading elements for marketing copy (or ensure a logical heading order).

Suggested change
>
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
</svg>
<span className="text-2xl font-bold">ObjectStack</span>
</div>
<h2 className="text-3xl font-bold leading-tight">
Build powerful business applications, faster.
</h2>
aria-hidden="true"
focusable="false"
>
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
</svg>
<span className="text-2xl font-bold">ObjectStack</span>
</div>
<p className="text-3xl font-bold leading-tight">
Build powerful business applications, faster.
</p>

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +12
const RouterLink = ({ href, className, children }: AuthLinkComponentProps) => (
<Link to={href} className={className}>{children}</Link>
);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RouterLink is duplicated across LoginPage/RegisterPage/ForgotPasswordPage with identical implementation. To reduce maintenance overhead, consider extracting a shared link wrapper (e.g. apps/console/src/components/RouterLink.tsx) and reusing it across auth pages.

Copilot uses AI. Check for mistakes.
Comment on lines +101 to +103
const successMsg = l.successDescription.includes('{{email}}')
? l.successDescription.replace('{{email}}', email)
: `${l.successDescription} ${email}`;
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new successDescription interpolation logic ({{email}} replacement / fallback append) isn’t covered by tests. Consider extending the existing “shows success message after submission” test to assert that the rendered success message includes the submitted email and handles the {{email}} placeholder as expected.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

登录页面优化及 /console 前缀配置导致 API 路径错误(宽屏模式、404 问题)

3 participants