diff options
Diffstat (limited to 'FrontEnd/src/app/views/timeline-common')
6 files changed, 84 insertions, 61 deletions
diff --git a/FrontEnd/src/app/views/timeline-common/Timeline.tsx b/FrontEnd/src/app/views/timeline-common/Timeline.tsx index fd051d45..9047919c 100644 --- a/FrontEnd/src/app/views/timeline-common/Timeline.tsx +++ b/FrontEnd/src/app/views/timeline-common/Timeline.tsx @@ -4,6 +4,7 @@ import clsx from "clsx"; import { TimelinePostInfo } from "@/services/timeline"; import TimelineItem from "./TimelineItem"; +import TimelineTop from "./TimelineTop"; export interface TimelinePostInfoEx extends TimelinePostInfo { deletable: boolean; @@ -13,6 +14,7 @@ export type TimelineDeleteCallback = (index: number, id: number) => void; export interface TimelineProps { className?: string; + style?: React.CSSProperties; posts: TimelinePostInfoEx[]; onDelete: TimelineDeleteCallback; onResize?: () => void; @@ -51,7 +53,12 @@ const Timeline: React.FC<TimelineProps> = (props) => { }, [posts, onDelete]); return ( - <div ref={props.containerRef} className={clsx("timeline", props.className)}> + <div + ref={props.containerRef} + style={props.style} + className={clsx("timeline", props.className)} + > + <TimelineTop height="56px" /> {(() => { const length = posts.length; return posts.map((post, i) => { diff --git a/FrontEnd/src/app/views/timeline-common/TimelineItem.tsx b/FrontEnd/src/app/views/timeline-common/TimelineItem.tsx index 4db23371..5ccc5523 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelineItem.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelineItem.tsx @@ -93,12 +93,12 @@ const TimelineItem: React.FC<TimelineItemProps> = (props) => { {current && <div className="timeline-line-segment current-end" />} </div> </div> - <div className="timeline-content-area"> + <div className="timeline-item-card"> <div> <span className="mr-2"> - <span className="text-primary white-space-no-wrap mr-2"> + <small className="text-secondary white-space-no-wrap mr-2"> {props.post.time.toLocaleString(i18n.languages)} - </span> + </small> <small className="text-dark">{props.post.author.nickname}</small> </span> {more != null ? ( @@ -138,33 +138,33 @@ const TimelineItem: React.FC<TimelineItemProps> = (props) => { } })()} </div> + {more != null && more.isOpen ? ( + <> + <div + className="position-absolute position-lt w-100 h-100 mask d-flex justify-content-center align-items-center" + onClick={more.toggle} + > + <Svg + src={trashIcon} + className="text-danger icon-button large" + onClick={(e) => { + toggleDeleteDialog(); + e.stopPropagation(); + }} + /> + </div> + {deleteDialog ? ( + <TimelinePostDeleteConfirmDialog + toggle={() => { + toggleDeleteDialog(); + more.toggle(); + }} + onConfirm={more.onDelete} + /> + ) : null} + </> + ) : null} </div> - {more != null && more.isOpen ? ( - <> - <div - className="position-absolute position-lt w-100 h-100 mask d-flex justify-content-center align-items-center" - onClick={more.toggle} - > - <Svg - src={trashIcon} - className="text-danger icon-button large" - onClick={(e) => { - toggleDeleteDialog(); - e.stopPropagation(); - }} - /> - </div> - {deleteDialog ? ( - <TimelinePostDeleteConfirmDialog - toggle={() => { - toggleDeleteDialog(); - more.toggle(); - }} - onConfirm={more.onDelete} - /> - ) : null} - </> - ) : null} </div> ); }; diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx index 6c2c43c1..036577b1 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx @@ -16,7 +16,6 @@ import Timeline, { TimelinePostInfoEx, TimelineDeleteCallback, } from "./Timeline"; -import TimelineTop from "./TimelineTop"; import TimelinePostEdit, { TimelinePostSendCallback } from "./TimelinePostEdit"; import { TimelineSyncStatus } from "./SyncStatusBadge"; @@ -48,13 +47,10 @@ export default function TimelinePageTemplateUI<TManageItems>( const { t } = useTranslation(); - const bottomSpaceRef = React.useRef<HTMLDivElement | null>(null); + const [bottomSpaceHeight, setBottomSpaceHeight] = React.useState<number>(0); const onPostEditHeightChange = React.useCallback((height: number): void => { - const { current: bottomSpaceDiv } = bottomSpaceRef; - if (bottomSpaceDiv != null) { - bottomSpaceDiv.style.height = `${height}px`; - } + setBottomSpaceHeight(height); if (height === 0) { const alertHost = getAlertHost(); if (alertHost != null) { @@ -178,6 +174,9 @@ export default function TimelinePageTemplateUI<TManageItems>( timelineBody = ( <Timeline + style={{ + minHeight: `calc(100vh - 56px - ${bottomSpaceHeight}px)`, + }} containerRef={timelineRef} posts={posts} onDelete={props.onDelete} @@ -188,7 +187,10 @@ export default function TimelinePageTemplateUI<TManageItems>( timelineBody = ( <> {timelineBody} - <div ref={bottomSpaceRef} className="flex-fix-length" /> + <div + style={{ height: bottomSpaceHeight }} + className="flex-fix-length" + /> <TimelinePostEdit className="fixed-bottom" onPost={props.onPost} @@ -226,7 +228,6 @@ export default function TimelinePageTemplateUI<TManageItems>( collapse={cardCollapse} toggleCollapse={toggleCardCollapse} /> - <TimelineTop height="56px" /> {timelineBody} </> ); diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx index 223525f9..ee49586e 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx @@ -6,9 +6,7 @@ import { TimelineChangePropertyRequest, } from "@/services/timeline"; -import OperationDialog, { - OperationSelectInputInfoOption, -} from "../common/OperationDialog"; +import OperationDialog from "../common/OperationDialog"; export interface TimelinePropertyInfo { title: string; @@ -45,12 +43,10 @@ const TimelinePropertyChangeDialog: React.FC<TimelinePropertyChangeDialogProps> { type: "select", label: "timeline.dialogChangeProperty.visibility", - options: kTimelineVisibilities.map<OperationSelectInputInfoOption>( - (v) => ({ - label: labelMap[v], - value: v, - }) - ), + options: kTimelineVisibilities.map((v) => ({ + label: labelMap[v], + value: v, + })), initValue: props.oldInfo.visibility, }, { @@ -64,13 +60,13 @@ const TimelinePropertyChangeDialog: React.FC<TimelinePropertyChangeDialogProps> onProcess={([newTitle, newVisibility, newDescription]) => { const req: TimelineChangePropertyRequest = {}; if (newTitle !== props.oldInfo.title) { - req.title = newTitle as string; + req.title = newTitle; } if (newVisibility !== props.oldInfo.visibility) { req.visibility = newVisibility as TimelineVisibility; } if (newDescription !== props.oldInfo.description) { - req.description = newDescription as string; + req.description = newDescription; } return props.onProcess(req); }} diff --git a/FrontEnd/src/app/views/timeline-common/timeline-background.svg b/FrontEnd/src/app/views/timeline-common/timeline-background.svg new file mode 100644 index 00000000..b72c448b --- /dev/null +++ b/FrontEnd/src/app/views/timeline-common/timeline-background.svg @@ -0,0 +1,4 @@ +<svg viewBox="0 0 100 80" xmlns="http://www.w3.org/2000/svg" stroke="rgba(255,196,0,0.6)">
+ <line x1="0" y1="0" x2="100" y2="40" stroke-width="5" />
+ <line x1="0" y1="80" x2="100" y2="40" stroke-width="5" />
+</svg>
\ No newline at end of file diff --git a/FrontEnd/src/app/views/timeline-common/timeline-common.sass b/FrontEnd/src/app/views/timeline-common/timeline-common.sass index 4151bfcc..8d9ee04d 100644 --- a/FrontEnd/src/app/views/timeline-common/timeline-common.sass +++ b/FrontEnd/src/app/views/timeline-common/timeline-common.sass @@ -4,8 +4,13 @@ z-index: 0 position: relative + background-image: url("views/timeline-common/timeline-background.svg") + background-size: 100% auto + background-repeat: no-repeat repeat + &-item - display: flex + position: relative + padding: 0.5em $timeline-line-width: 7px $timeline-line-node-radius: 18px @@ -30,11 +35,15 @@ $timeline-line-color-current: #36c2e6 .timeline-line &-area-container + position: absolute display: flex justify-content: flex-end padding-right: 5px + z-index: 1 - flex: 0 0 auto + top: 0em + bottom: 0em + left: 0.5em width: 60px &-area @@ -48,14 +57,14 @@ $timeline-line-color-current: #36c2e6 background: $timeline-line-color &.start - height: 14px + height: 1.4em flex: 0 0 auto &.end flex: 1 1 auto &.current-end - height: 20px + height: 2em flex: 0 0 auto background: linear-gradient($timeline-line-color-current, transparent) @@ -78,13 +87,16 @@ $timeline-line-color-current: #36c2e6 animation-name: timeline-line-node-noncurrent .timeline-top - display: flex - justify-content: space-between + position: relative + text-align: right .timeline-line-segment flex: 1 1 auto .current + &.timeline-item + padding-bottom: 2.5em + .timeline-line &-segment @@ -97,9 +109,15 @@ $timeline-line-color-current: #36c2e6 &-node animation-name: timeline-line-node-current -.timeline-content-area - padding: 10px 0 - flex-grow: 1 +.timeline-item-card + @extend .cru-card + @extend .clearfix + position: relative + padding: 0.5em 2em 0.5em 60px + transition: background 0.5s + + &:hover + background: $gray-200 .timeline-item-delete-button position: absolute @@ -121,9 +139,6 @@ $timeline-line-color-current: #36c2e6 background: change-color($color: white, $alpha: 0.8) z-index: 100 -.timeline-page-top-space - transition: height 0.5s - .timeline-sync-state-badge font-size: 0.8em padding: 3px 8px |