This is an automated email from the ASF dual-hosted git repository.

shuai pushed a commit to branch feat/1.4.3/ui
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git

commit 58f2191d51ad41d14be69e2fc5b7fe1b7f38a3b7
Author: shuai <[email protected]>
AuthorDate: Mon Dec 16 11:00:34 2024 +0800

    fix: Top list UI optimization
---
 ui/src/common/color.scss                       |   2 +-
 ui/src/components/PinList/index.tsx            |  60 +++++++++++
 ui/src/components/QuestionList/index.tsx       | 137 +++++++++++++------------
 ui/src/components/QuestionListLoader/index.tsx |  22 +++-
 ui/src/components/SideNav/index.tsx            |   4 +-
 ui/src/components/index.ts                     |   2 +
 6 files changed, 155 insertions(+), 72 deletions(-)

diff --git a/ui/src/common/color.scss b/ui/src/common/color.scss
index a2dd55fc..e82624fe 100644
--- a/ui/src/common/color.scss
+++ b/ui/src/common/color.scss
@@ -37,7 +37,7 @@
   --an-editor-toolbar-hover: #f8f9fa;
   --ans-editor-toolbar-focus: #dae0e5;
   --an-editor-placeholder-color: #6c757d;
-  --an-side-nav-link-hover-color: black;
+  --an-side-nav-link-hover-color: rgba(0, 0, 0, .85);
   --an-invite-answer-item-active: #e9ecef;
   --an-alert-exist-color: #055160;
 }
diff --git a/ui/src/components/PinList/index.tsx 
b/ui/src/components/PinList/index.tsx
new file mode 100644
index 00000000..059ca422
--- /dev/null
+++ b/ui/src/components/PinList/index.tsx
@@ -0,0 +1,60 @@
+import { FC } from 'react';
+import { ListGroup, Stack, Card } from 'react-bootstrap';
+import { NavLink } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+
+import { Counts } from '@/components';
+import { pathFactory } from '@/router/pathFactory';
+
+interface IProps {
+  data: any[];
+}
+
+const PinList: FC<IProps> = ({ data }) => {
+  const { t } = useTranslation('translation', { keyPrefix: 'question' });
+  if (!data?.length) return null;
+
+  return (
+    <ListGroup.Item className="py-3 px-0 border-start-0 border-end-0">
+      <Stack
+        direction="horizontal"
+        gap={3}
+        className="overflow-x-auto align-items-stretch">
+        {data.map((item) => {
+          return (
+            <Card
+              key={item.id}
+              style={{
+                minWidth: '238px',
+                width: `${100 / data.length}%`,
+              }}>
+              <Card.Body>
+                <h6 className="text-wrap text-break">
+                  <NavLink
+                    to={pathFactory.questionLanding(item.id, item.url_title)}
+                    className="link-dark text-truncate-2">
+                    {item.title}
+                    {item.status === 2 ? ` [${t('closed')}]` : ''}
+                  </NavLink>
+                </h6>
+
+                <Counts
+                  data={{
+                    votes: item.vote_count,
+                    answers: item.answer_count,
+                    views: item.view_count,
+                  }}
+                  isAccepted={item.accepted_answer_id >= 1}
+                  showViews={false}
+                  className="mt-2 mt-md-0 small text-secondary"
+                />
+              </Card.Body>
+            </Card>
+          );
+        })}
+      </Stack>
+    </ListGroup.Item>
+  );
+};
+
+export default PinList;
diff --git a/ui/src/components/QuestionList/index.tsx 
b/ui/src/components/QuestionList/index.tsx
index 8796a975..256dbfb4 100644
--- a/ui/src/components/QuestionList/index.tsx
+++ b/ui/src/components/QuestionList/index.tsx
@@ -32,7 +32,7 @@ import {
   QueryGroup,
   QuestionListLoader,
   Counts,
-  Icon,
+  PinList,
 } from '@/components';
 import * as Type from '@/common/interface';
 import { useSkeletonControl } from '@/hooks';
@@ -69,6 +69,13 @@ const QuestionList: FC<Props> = ({
   const pageSize = 20;
   const count = data?.count || 0;
   const orderKeys = orderList || QUESTION_ORDER_KEYS;
+  const pinData =
+    source === 'questions'
+      ? data?.list?.filter((v) => v.pin === 2).slice(0, 3)
+      : [];
+  const renderData = data?.list?.filter(
+    (v) => pinData.findIndex((p) => p.id === v.id) === -1,
+  );
 
   return (
     <div>
@@ -90,74 +97,72 @@ const QuestionList: FC<Props> = ({
         {isSkeletonShow ? (
           <QuestionListLoader />
         ) : (
-          data?.list?.map((li) => {
-            return (
-              <ListGroup.Item
-                key={li.id}
-                className="bg-transparent py-3 px-2 border-start-0 
border-end-0">
-                <div className="d-flex flex-wrap text-secondary small mb-12">
-                  <BaseUserCard
-                    data={li.operator}
-                    className="me-1"
-                    avatarClass="me-2"
-                  />
-                  •
-                  <FormatTime
-                    time={
-                      curOrder === 'active' ? li.operated_at : li.created_at
-                    }
-                    className="text-secondary ms-1 flex-shrink-0"
-                    preFix={
-                      curOrder === 'active' ? t(li.operation_type) : t('asked')
-                    }
-                  />
-                </div>
-                <h5 className="text-wrap text-break">
-                  {li.pin === 2 && (
-                    <Icon
-                      name="pin-fill"
+          <>
+            <PinList data={pinData} />
+            {renderData?.map((li) => {
+              return (
+                <ListGroup.Item
+                  key={li.id}
+                  className="bg-transparent py-3 px-2 border-start-0 
border-end-0">
+                  <div className="d-flex flex-wrap text-secondary small mb-12">
+                    <BaseUserCard
+                      data={li.operator}
                       className="me-1"
-                      title={t('pinned', { keyPrefix: 'btns' })}
+                      avatarClass="me-2"
+                    />
+                    •
+                    <FormatTime
+                      time={
+                        curOrder === 'active' ? li.operated_at : li.created_at
+                      }
+                      className="text-secondary ms-1 flex-shrink-0"
+                      preFix={
+                        curOrder === 'active'
+                          ? t(li.operation_type)
+                          : t('asked')
+                      }
                     />
-                  )}
-                  <NavLink
-                    to={pathFactory.questionLanding(li.id, li.url_title)}
-                    className="link-dark">
-                    {li.title}
-                    {li.status === 2 ? ` [${t('closed')}]` : ''}
-                  </NavLink>
-                </h5>
-                <p className="mb-2 small text-body text-truncate-2">
-                  {li.description}
-                </p>
+                  </div>
+                  <h5 className="text-wrap text-break">
+                    <NavLink
+                      to={pathFactory.questionLanding(li.id, li.url_title)}
+                      className="link-dark">
+                      {li.title}
+                      {li.status === 2 ? ` [${t('closed')}]` : ''}
+                    </NavLink>
+                  </h5>
+                  <p className="mb-2 small text-body text-truncate-2">
+                    {li.description}
+                  </p>
 
-                <div className="question-tags mb-2">
-                  {Array.isArray(li.tags)
-                    ? li.tags.map((tag, index) => {
-                        return (
-                          <Tag
-                            key={tag.slug_name}
-                            className={`${li.tags.length - 1 === index ? '' : 
'me-1'}`}
-                            data={tag}
-                          />
-                        );
-                      })
-                    : null}
-                </div>
-                <div className="small text-secondary">
-                  <Counts
-                    data={{
-                      votes: li.vote_count,
-                      answers: li.answer_count,
-                      views: li.view_count,
-                    }}
-                    isAccepted={li.accepted_answer_id >= 1}
-                    className="mt-2 mt-md-0"
-                  />
-                </div>
-              </ListGroup.Item>
-            );
-          })
+                  <div className="question-tags mb-2">
+                    {Array.isArray(li.tags)
+                      ? li.tags.map((tag, index) => {
+                          return (
+                            <Tag
+                              key={tag.slug_name}
+                              className={`${li.tags.length - 1 === index ? '' 
: 'me-1'}`}
+                              data={tag}
+                            />
+                          );
+                        })
+                      : null}
+                  </div>
+                  <div className="small text-secondary">
+                    <Counts
+                      data={{
+                        votes: li.vote_count,
+                        answers: li.answer_count,
+                        views: li.view_count,
+                      }}
+                      isAccepted={li.accepted_answer_id >= 1}
+                      className="mt-2 mt-md-0"
+                    />
+                  </div>
+                </ListGroup.Item>
+              );
+            })}
+          </>
         )}
       </ListGroup>
       {count <= 0 && !isLoading && <Empty />}
diff --git a/ui/src/components/QuestionListLoader/index.tsx 
b/ui/src/components/QuestionListLoader/index.tsx
index 049cb6d0..e76aa00d 100644
--- a/ui/src/components/QuestionListLoader/index.tsx
+++ b/ui/src/components/QuestionListLoader/index.tsx
@@ -30,22 +30,36 @@ const Index: FC<Props> = ({ count = 10 }) => {
     <>
       {list.map((v) => (
         <ListGroupItem
-          className="bg-transparent py-3 px-0 border-start-0 border-end-0 
placeholder-glow"
+          className="bg-transparent py-3 px-2 border-start-0 border-end-0 
placeholder-glow"
           key={v}>
           <div
-            className="placeholder w-100 h5 align-top"
+            className="placeholder h5 align-top d-block"
+            style={{ height: '21px', width: '35%' }}
+          />
+
+          <div
+            className="placeholder w-75 h5 align-top"
             style={{ height: '24px' }}
           />
 
           <div
-            className="placeholder w-75 d-block align-top mb-2"
+            className="placeholder w-100 d-block align-top mb-2"
+            style={{ height: '21px' }}
+          />
+          <div
+            className="placeholder w-100 d-block align-top mb-2"
             style={{ height: '21px' }}
           />
 
           <div
-            className="placeholder w-50 align-top"
+            className="placeholder w-50 align-top mb-2"
             style={{ height: '24px' }}
           />
+
+          <div
+            className="placeholder w-25 align-top d-block"
+            style={{ height: '21px' }}
+          />
         </ListGroupItem>
       ))}
     </>
diff --git a/ui/src/components/SideNav/index.tsx 
b/ui/src/components/SideNav/index.tsx
index e2acf127..4af827f5 100644
--- a/ui/src/components/SideNav/index.tsx
+++ b/ui/src/components/SideNav/index.tsx
@@ -81,6 +81,7 @@ const Index: FC = () => {
               </div>
               {can_revision && (
                 <NavLink to="/review" className="nav-link">
+                  <Icon name="shield-fill-check" className="me-2" />
                   <span>{t('header.nav.review')}</span>
                   <span className="float-end">
                     {revision > 99 ? '99+' : revision > 0 ? revision : ''}
@@ -90,7 +91,8 @@ const Index: FC = () => {
 
               {userInfo?.role_id === 2 ? (
                 <NavLink to="/admin" className="nav-link">
-                  {t('header.nav.admin')}
+                  <Icon name="gear-fill" className="me-2" />
+                  <span>{t('header.nav.admin')}</span>
                 </NavLink>
               ) : null}
             </>
diff --git a/ui/src/components/index.ts b/ui/src/components/index.ts
index 44dc1516..400c6b6f 100644
--- a/ui/src/components/index.ts
+++ b/ui/src/components/index.ts
@@ -61,6 +61,7 @@ import SideNav from './SideNav';
 import PluginRender from './PluginRender';
 import HighlightText from './HighlightText';
 import CardBadge from './CardBadge';
+import PinList from './PinList';
 
 export {
   Avatar,
@@ -109,5 +110,6 @@ export {
   PluginRender,
   HighlightText,
   CardBadge,
+  PinList,
 };
 export type { EditorRef, JSONSchema, UISchema };

Reply via email to