aboutsummaryrefslogtreecommitdiff
path: root/Timeline
diff options
context:
space:
mode:
Diffstat (limited to 'Timeline')
-rw-r--r--Timeline/ClientApp/src/app/locales/en/translation.ts5
-rw-r--r--Timeline/ClientApp/src/app/locales/scheme.ts5
-rw-r--r--Timeline/ClientApp/src/app/locales/zh/translation.ts5
-rw-r--r--Timeline/ClientApp/src/app/timeline/Timeline.tsx5
-rw-r--r--Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx66
-rw-r--r--Timeline/ClientApp/src/app/timeline/timeline-ui.sass18
-rw-r--r--Timeline/ClientApp/src/app/timeline/timeline.sass6
7 files changed, 98 insertions, 12 deletions
diff --git a/Timeline/ClientApp/src/app/locales/en/translation.ts b/Timeline/ClientApp/src/app/locales/en/translation.ts
index 6abe910e..2f8fb312 100644
--- a/Timeline/ClientApp/src/app/locales/en/translation.ts
+++ b/Timeline/ClientApp/src/app/locales/en/translation.ts
@@ -92,6 +92,11 @@ const translation: TranslationResource = {
'This is a dangerous action. If you are sure to delete timeline<1>{{name}}</1>, please input its name below and click confirm button.',
notMatch: 'Name does not match.',
},
+ postSyncState: {
+ syncing: 'Syncing',
+ synced: 'Synced',
+ offline: 'Offline',
+ },
post: {
deleteDialog: {
title: 'Confirm Delete',
diff --git a/Timeline/ClientApp/src/app/locales/scheme.ts b/Timeline/ClientApp/src/app/locales/scheme.ts
index 19ac6c31..7aa7e125 100644
--- a/Timeline/ClientApp/src/app/locales/scheme.ts
+++ b/Timeline/ClientApp/src/app/locales/scheme.ts
@@ -83,6 +83,11 @@ export default interface TranslationResource {
inputPrompt: string;
notMatch: string;
};
+ postSyncState: {
+ syncing: string;
+ synced: string;
+ offline: string;
+ };
post: {
deleteDialog: {
title: string;
diff --git a/Timeline/ClientApp/src/app/locales/zh/translation.ts b/Timeline/ClientApp/src/app/locales/zh/translation.ts
index 372979c0..35cfa38c 100644
--- a/Timeline/ClientApp/src/app/locales/zh/translation.ts
+++ b/Timeline/ClientApp/src/app/locales/zh/translation.ts
@@ -88,6 +88,11 @@ const translation: TranslationResource = {
'这是一个危险的操作。如果您确认要删除时间线<1>{{name}}</1>,请在下面输入它的名字并点击确认。',
notMatch: '名字不匹配',
},
+ postSyncState: {
+ syncing: '同步中',
+ synced: '同步成功',
+ offline: '离线',
+ },
post: {
deleteDialog: {
title: '确认删除',
diff --git a/Timeline/ClientApp/src/app/timeline/Timeline.tsx b/Timeline/ClientApp/src/app/timeline/Timeline.tsx
index 849933cf..7c3a93fb 100644
--- a/Timeline/ClientApp/src/app/timeline/Timeline.tsx
+++ b/Timeline/ClientApp/src/app/timeline/Timeline.tsx
@@ -53,10 +53,7 @@ const Timeline: React.FC<TimelineProps> = (props) => {
return (
<div
ref={props.containerRef}
- className={clsx(
- 'container-fluid d-flex flex-column position-relative',
- props.className
- )}
+ className={clsx('container-fluid timeline', props.className)}
>
<div className="timeline-enter-animation-mask" />
{(() => {
diff --git a/Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx b/Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx
index 3c8e312c..0d8ad278 100644
--- a/Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx
+++ b/Timeline/ClientApp/src/app/timeline/TimelinePageTemplateUI.tsx
@@ -8,7 +8,7 @@ import arrowsAngleContractIcon from 'bootstrap-icons/icons/arrows-angle-contract
import arrowsAngleExpandIcon from 'bootstrap-icons/icons/arrows-angle-expand.svg';
import { getAlertHost } from '../common/alert-service';
-import { useEventEmiiter } from '../common';
+import { useEventEmiiter, UiLogicError } from '../common';
import {
TimelineInfo,
TimelinePostListState,
@@ -23,6 +23,53 @@ import Timeline, {
import AppBar from '../common/AppBar';
import TimelinePostEdit, { TimelinePostSendCallback } from './TimelinePostEdit';
+const TimelinePostSyncStateBadge: React.FC<{
+ state: 'syncing' | 'synced' | 'offline';
+}> = ({ state }) => {
+ const { t } = useTranslation();
+
+ return (
+ <div className="timeline-sync-state-badge">
+ {(() => {
+ switch (state) {
+ case 'syncing': {
+ return (
+ <>
+ <span className="timeline-sync-state-badge-pin bg-warning" />
+ <span className="text-warning">
+ {t('timeline.postSyncState.syncing')}
+ </span>
+ </>
+ );
+ }
+ case 'synced': {
+ return (
+ <>
+ <span className="timeline-sync-state-badge-pin bg-success" />
+ <span className="text-success">
+ {t('timeline.postSyncState.synced')}
+ </span>
+ </>
+ );
+ }
+ case 'offline': {
+ return (
+ <>
+ <span className="timeline-sync-state-badge-pin bg-danger" />
+ <span className="text-danger">
+ {t('timeline.postSyncState.offline')}
+ </span>
+ </>
+ );
+ }
+ default:
+ throw new UiLogicError('Unknown sync state.');
+ }
+ })()}
+ </div>
+ );
+};
+
export interface TimelineCardComponentProps<TManageItems> {
timeline: TimelineInfo;
onManage?: (item: TManageItems | 'property') => void;
@@ -147,7 +194,7 @@ export default function TimelinePageTemplateUI<TManageItems>(
} else {
if (timeline != null) {
let timelineBody: React.ReactElement;
- if (postListState != null) {
+ if (postListState != null && postListState.state !== 'loading') {
if (postListState.state === 'forbid') {
timelineBody = (
<p className="text-danger">{t('timeline.messageCantSee')}</p>
@@ -165,12 +212,15 @@ export default function TimelinePageTemplateUI<TManageItems>(
);
timelineBody = (
- <Timeline
- containerRef={timelineRef}
- posts={posts}
- onDelete={props.onDelete}
- onResize={triggerResizeEvent}
- />
+ <div className="position-relative">
+ <TimelinePostSyncStateBadge state={postListState.state} />
+ <Timeline
+ containerRef={timelineRef}
+ posts={posts}
+ onDelete={props.onDelete}
+ onResize={triggerResizeEvent}
+ />
+ </div>
);
if (props.onPost != null) {
timelineBody = (
diff --git a/Timeline/ClientApp/src/app/timeline/timeline-ui.sass b/Timeline/ClientApp/src/app/timeline/timeline-ui.sass
index b92327bd..952e4659 100644
--- a/Timeline/ClientApp/src/app/timeline/timeline-ui.sass
+++ b/Timeline/ClientApp/src/app/timeline/timeline-ui.sass
@@ -16,3 +16,21 @@
.timeline-page-top-space
transition: height 0.5s
+.timeline-sync-state-badge
+ position: absolute
+ top: 0
+ right: 0
+ z-index: 1
+ font-size: 0.8em
+ margin-top: 4px
+ padding: 3px 8px
+ border-radius: 5px
+ background: #e8fbff
+
+.timeline-sync-state-badge-pin
+ display: inline-block
+ width: 0.4em
+ height: 0.4em
+ border-radius: 50%
+ vertical-align: middle
+ margin-right: 0.6em
diff --git a/Timeline/ClientApp/src/app/timeline/timeline.sass b/Timeline/ClientApp/src/app/timeline/timeline.sass
index 4f69295b..b224e973 100644
--- a/Timeline/ClientApp/src/app/timeline/timeline.sass
+++ b/Timeline/ClientApp/src/app/timeline/timeline.sass
@@ -1,5 +1,11 @@
@use 'sass:color'
+.timeline
+ display: flex
+ flex-direction: column
+ z-index: 0
+ position: relative
+
@keyframes timeline-enter-animation-mask-animation
to
height: 0