feat(admin): 分区增删、资料设置、操作条与交互收尾
- POST/DELETE /api/categories(需登录,级联,local 保护) - profile 设置(头像/名称/角色/简介/位置)应用到资料卡 - 详情操作条:浏览 +1、点赞切换、分享复制、跳转外链 - 编辑按钮垂直居中且留 12px;设置页按钮上间距、保存 Toast、Tabs 去滚动条 - 登录密码可见切换 - 测试 48 passed
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Button, FormField, Icon, Input, Modal, Notice, Space, Text } from '@stash/ui'
|
||||
import { Button, FormField, Icon, Modal, Notice, Space, Text } from '@stash/ui'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { login, setup, type SessionState } from '../../auth'
|
||||
import { PasswordInput } from './PasswordInput'
|
||||
|
||||
/**
|
||||
* 登录弹窗:首次使用显示「设置密码 + 确认」,之后只显示密码。
|
||||
@@ -84,32 +85,24 @@ export function LoginDialog({ open, hasAdmin, onClose, onSuccess }: LoginDialogP
|
||||
)}
|
||||
|
||||
<FormField label="密码" htmlFor="login-password" required>
|
||||
<Input
|
||||
<PasswordInput
|
||||
id="login-password"
|
||||
type="password"
|
||||
icon="lock_line"
|
||||
placeholder="输入密码"
|
||||
value={password}
|
||||
autoFocus
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') void submit()
|
||||
}}
|
||||
onChange={setPassword}
|
||||
onEnter={() => void submit()}
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
{isSetup && (
|
||||
<FormField label="确认密码" htmlFor="login-confirm" required>
|
||||
<Input
|
||||
<PasswordInput
|
||||
id="login-confirm"
|
||||
type="password"
|
||||
icon="keyhole_line"
|
||||
placeholder="再输入一次"
|
||||
value={confirm}
|
||||
onChange={(event) => setConfirm(event.target.value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') void submit()
|
||||
}}
|
||||
onChange={setConfirm}
|
||||
onEnter={() => void submit()}
|
||||
/>
|
||||
</FormField>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Icon, IconButton, Input } from '@stash/ui'
|
||||
import { useState } from 'react'
|
||||
|
||||
/**
|
||||
* 语言无关的密码可见切换:右侧一个眼睛按钮,切换 input type。
|
||||
* 错误提示后再点仍然有效(状态在组件里,不会被错误重置)。
|
||||
*/
|
||||
type PasswordInputProps = {
|
||||
id: string
|
||||
value: string
|
||||
placeholder?: string
|
||||
autoFocus?: boolean
|
||||
onChange: (value: string) => void
|
||||
onEnter?: () => void
|
||||
}
|
||||
|
||||
export function PasswordInput({
|
||||
id,
|
||||
value,
|
||||
placeholder,
|
||||
autoFocus = false,
|
||||
onChange,
|
||||
onEnter,
|
||||
}: PasswordInputProps) {
|
||||
const [visible, setVisible] = useState(false)
|
||||
|
||||
return (
|
||||
<div className="password-field">
|
||||
<Input
|
||||
id={id}
|
||||
type={visible ? 'text' : 'password'}
|
||||
icon="lock_line"
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
autoFocus={autoFocus}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') onEnter?.()
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
label={visible ? '隐藏密码' : '显示密码'}
|
||||
icon={<Icon name={visible ? 'eye_close_line' : 'eye_line'} />}
|
||||
onClick={() => setVisible((current) => !current)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user