Merge pull request #496 from answerdev/feat/1.1.3/ui

Feat/1.1.3/UI
This commit is contained in:
dashuai 2023-08-28 10:48:43 +08:00 committed by GitHub
commit 9ee06d73a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 105 additions and 52 deletions

View File

@ -1263,12 +1263,14 @@ ui:
site_name:
label: Site name
msg: Site name cannot be empty.
msg_max_length: Site name must be at maximum 30 characters in length.
site_url:
label: Site URL
text: The address of your site.
msg:
empty: Site URL cannot be empty.
incorrect: Site URL incorrect format.
max_length: Site URL must be at maximum 512 characters in length.
contact_email:
label: Contact email
text: Email address of key contact responsible for this site.
@ -1283,12 +1285,15 @@ ui:
label: Name
msg: Name cannot be empty.
character: 'Must use the character set "a-z", "0-9", " - . _"'
msg_max_length: Name must be at maximum 30 characters in length.
admin_password:
label: Password
text: >-
You will need this password to log in. Please store it in a secure
location.
msg: Password cannot be empty.
msg_min_length: Password must be at least 8 characters in length.
msg_max_length: Password must be at maximum 32 characters in length.
admin_email:
label: Email
text: You will need this email to log in.

View File

@ -12,6 +12,7 @@ interface Props {
avatarSearchStr?: string;
className?: string;
avatarClass?: string;
nameMaxWidth?: string;
}
const Index: FC<Props> = ({
@ -22,11 +23,14 @@ const Index: FC<Props> = ({
className = 'small',
avatarSearchStr = 's=48',
showReputation = true,
nameMaxWidth = '300px',
}) => {
return (
<div className={`d-flex align-items-center text-secondary ${className}`}>
{data?.status !== 'deleted' ? (
<Link to={`/users/${data?.username}`}>
<Link
to={`/users/${data?.username}`}
className="d-flex align-items-center">
{showAvatar && (
<Avatar
avatar={data?.avatar}
@ -36,7 +40,9 @@ const Index: FC<Props> = ({
alt={data?.display_name}
/>
)}
<span className="me-1 text-truncate-1" style={{ maxWidth: '300px' }}>
<span
className="me-1 name-ellipsis"
style={{ maxWidth: nameMaxWidth }}>
{data?.display_name}
</span>
</Link>
@ -51,9 +57,7 @@ const Index: FC<Props> = ({
alt={data?.display_name}
/>
)}
<span className="me-1 text-truncate-1" style={{ maxWidth: '300px' }}>
{data?.display_name}
</span>
<span className="me-1 name-ellipsis">{data?.display_name}</span>
</>
)}

View File

@ -1,5 +1,5 @@
import { FC, useContext, useEffect } from 'react';
import { Dropdown, OverlayTrigger, Tooltip, Button } from 'react-bootstrap';
import { Dropdown, Button } from 'react-bootstrap';
import { EditorContext } from './EditorContext';
@ -49,28 +49,27 @@ const ToolItem: FC<IProps> = (props) => {
}, []);
const btnRender = () => (
<OverlayTrigger placement="bottom" overlay={<Tooltip>{tip}</Tooltip>}>
<Button
variant="link"
className={`p-0 b-0 btn-no-border toolbar icon-${label} ${
disable ? 'disabled' : ''
} `}
disabled={disable}
tabIndex={-1}
onClick={(e) => {
e.preventDefault();
if (typeof onClick === 'function') {
onClick();
}
}}
onBlur={(e) => {
e.preventDefault();
if (typeof onBlur === 'function') {
onBlur();
}
}}
/>
</OverlayTrigger>
<Button
variant="link"
title={tip}
className={`p-0 b-0 btn-no-border toolbar icon-${label} ${
disable ? 'disabled' : ''
} `}
disabled={disable}
tabIndex={-1}
onClick={(e) => {
e.preventDefault();
if (typeof onClick === 'function') {
onClick();
}
}}
onBlur={(e) => {
e.preventDefault();
if (typeof onBlur === 'function') {
onBlur();
}
}}
/>
);
if (!context) {

View File

@ -141,6 +141,13 @@ img[src=""] {
}
}
.name-ellipsis {
display: inline-block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.text-truncate-1,
.text-truncate-2,
.text-truncate-3,

View File

@ -155,7 +155,7 @@ const Answers: FC = () => {
<td>{li.vote_count}</td>
<td>
<Stack>
<BaseUserCard data={li.user_info} />
<BaseUserCard data={li.user_info} nameMaxWidth="200px" />
<FormatTime
className="small text-secondary"

View File

@ -160,7 +160,7 @@ const Questions: FC = () => {
</td>
<td>
<Stack>
<BaseUserCard data={li.user_info} />
<BaseUserCard data={li.user_info} nameMaxWidth="130px" />
<FormatTime
className="small text-secondary"
time={li.create_time}

View File

@ -254,6 +254,7 @@ const Users: FC = () => {
avatarSearchStr="s=48"
avatarClass="me-2"
showReputation={false}
nameMaxWidth="160px"
/>
</td>
<td>{formatCount(user.rank)}</td>

View File

@ -28,6 +28,15 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
};
}
if (site_name.value && site_name.value.length > 30) {
bol = false;
data.site_url = {
value: site_name.value,
isInvalid: true,
errorMsg: t('site_name.msg_max_length'),
};
}
if (!site_url.value) {
bol = false;
data.site_url = {
@ -36,6 +45,7 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
errorMsg: t('site_name.msg.empty'),
};
}
const reg = /^(http|https):\/\//g;
if (site_url.value && !site_url.value.match(reg)) {
bol = false;
@ -44,6 +54,13 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
isInvalid: true,
errorMsg: t('site_url.msg.incorrect'),
};
} else if (site_url.value.length > 512) {
bol = false;
data.site_url = {
value: site_url.value,
isInvalid: true,
errorMsg: t('site_url.msg.max_length'),
};
}
if (!contact_email.value) {
@ -78,6 +95,13 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
isInvalid: true,
errorMsg: t('admin_name.character'),
};
} else if (data.name.value.length > 30) {
bol = false;
data.name = {
value: data.name.value,
isInvalid: true,
errorMsg: t('admin_name.msg_max_length'),
};
}
if (!password.value) {
@ -89,6 +113,24 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
};
}
if (password.value && password.value.length < 4) {
bol = false;
data.password = {
value: data.password.value,
isInvalid: true,
errorMsg: t('admin_password.msg_min_length'),
};
}
if (password.value && password.value.length > 32) {
bol = false;
data.password = {
value: data.password.value,
isInvalid: true,
errorMsg: t('admin_password.msg_max_length'),
};
}
if (!email.value) {
bol = false;
data.email = {
@ -132,7 +174,6 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
required
value={data.site_name.value}
isInvalid={data.site_name.isInvalid}
maxLength={30}
onChange={(e) => {
changeCallback({
site_name: {
@ -153,7 +194,6 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
required
value={data.site_url.value}
isInvalid={data.site_url.isInvalid}
maxLength={512}
onChange={(e) => {
changeCallback({
site_url: {
@ -220,7 +260,6 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
required
value={data.name.value}
isInvalid={data.name.isInvalid}
maxLength={30}
onChange={(e) => {
changeCallback({
name: {
@ -241,7 +280,6 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
<Form.Control
required
type="password"
maxLength={32}
value={data.password.value}
isInvalid={data.password.isInvalid}
onChange={(e) => {

View File

@ -23,7 +23,7 @@ import {
const Index: FC = () => {
const { t } = useTranslation('translation', { keyPrefix: 'install' });
const [step, setStep] = useState(1);
const [step, setStep] = useState(4);
const [loading, setLoading] = useState(true);
const [errorData, setErrorData] = useState<{ [propName: string]: any }>({
msg: '',

View File

@ -40,18 +40,22 @@ const SearchQuestion = ({ similarQuestions }) => {
{item.accepted_answer ? (
<span className="ms-3 text-success">
<Icon type="bi" name="check-circle-fill" />
<span className="ms-1">{item.answer_count}</span>
<span className="ms-1">
{t('x_answers', {
keyPrefix: 'question',
count: item.answer_count,
})}
</span>
</span>
) : (
item.answer_count > 0 && (
<span className="ms-3">
<Icon
type="bi"
name="chat-square-text-fill"
className="text-secondary"
/>
<span className="ms-1 text-primary">
{item.answer_count}
<span className="ms-3 text-secondary">
<Icon type="bi" name="chat-square-text-fill" />
<span className="ms-1">
{t('x_answers', {
keyPrefix: 'question',
count: item.answer_count,
})}
</span>
</span>
)

View File

@ -187,7 +187,6 @@ const Index: React.FC = () => {
tabIndex={1}
type="password"
// value={formData.pass.value}
maxLength={32}
isInvalid={formData.pass.isInvalid}
onChange={(e) =>
handleChange({

View File

@ -127,7 +127,6 @@ const Index: React.FC = () => {
autoComplete="off"
required
type="password"
maxLength={32}
isInvalid={formData.pass.isInvalid}
onChange={(e) => {
handleChange({
@ -150,7 +149,6 @@ const Index: React.FC = () => {
autoComplete="off"
required
type="password"
maxLength={32}
isInvalid={formData.passSecond.isInvalid}
onChange={(e) => {
handleChange({

View File

@ -184,7 +184,6 @@ const Index: React.FC<Props> = ({ callback }) => {
autoComplete="off"
required
type="password"
maxLength={32}
isInvalid={formData.pass.isInvalid}
value={formData.pass.value}
onChange={(e) =>

View File

@ -158,7 +158,6 @@ const Index: FC = () => {
autoComplete="new-password"
required
type="password"
maxLength={32}
isInvalid={formData.pass.isInvalid}
onChange={(e) =>
handleChange({

View File

@ -185,7 +185,6 @@ const Index: FC = () => {
autoComplete="off"
required
type="password"
maxLength={32}
isInvalid={formData.pass.isInvalid}
onChange={(e) =>
handleChange({
@ -208,7 +207,6 @@ const Index: FC = () => {
autoComplete="off"
required
type="password"
maxLength={32}
isInvalid={formData.pass2.isInvalid}
onChange={(e) =>
handleChange({

View File

@ -72,7 +72,9 @@ export const addComment = (params) => {
};
export const queryTags = (tag: string) => {
return request.get(`/answer/api/v1/question/tags?tag=${tag}`);
return request.get(
`/answer/api/v1/question/tags?tag=${encodeURIComponent(tag)}`,
);
};
export const useQueryAnswerInfo = (id: string) => {