From 4453e7710dcaf06487e7861114d08e9f28b42a3a Mon Sep 17 00:00:00 2001 From: Ludwig Kristoffersson Date: Mon, 24 Apr 2023 22:06:53 +0200 Subject: [PATCH 1/5] fix issue where separate youtube and kth play lists would render on mobile --- .../src/components/course/course-content/course-content.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web-ui/src/components/course/course-content/course-content.tsx b/web-ui/src/components/course/course-content/course-content.tsx index aae6029..abf3688 100644 --- a/web-ui/src/components/course/course-content/course-content.tsx +++ b/web-ui/src/components/course/course-content/course-content.tsx @@ -80,12 +80,12 @@ export default function CourseContent(props: CourseContentProps) { {/* Separate KTH Play and YouTube videos on desktop */} - + KTH Play - - + + Youtube From 4a08d0f5d62277dbae90c70ca1b28a6f45aa2a79 Mon Sep 17 00:00:00 2001 From: Ludwig Kristoffersson Date: Mon, 24 Apr 2023 22:49:34 +0200 Subject: [PATCH 2/5] add pagination to lecture-list --- .../lecture/lecture-list/lecture-list.less | 14 ++++ .../lecture/lecture-list/lecture-list.tsx | 68 ++++++++++++++++--- 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/web-ui/src/components/lecture/lecture-list/lecture-list.less b/web-ui/src/components/lecture/lecture-list/lecture-list.less index 6a5a10b..f7f2ae4 100644 --- a/web-ui/src/components/lecture/lecture-list/lecture-list.less +++ b/web-ui/src/components/lecture/lecture-list/lecture-list.less @@ -48,4 +48,18 @@ width: 100% !important; } } + + .item { + margin-bottom: 20px; + } +} + +.load_more { + width: 100%; + margin-top: 80px; + margin-bottom: 200px; +} + +.hits { + margin-top: 10px; } diff --git a/web-ui/src/components/lecture/lecture-list/lecture-list.tsx b/web-ui/src/components/lecture/lecture-list/lecture-list.tsx index ba8462c..cd8b242 100644 --- a/web-ui/src/components/lecture/lecture-list/lecture-list.tsx +++ b/web-ui/src/components/lecture/lecture-list/lecture-list.tsx @@ -1,6 +1,6 @@ import styles from './lecture-list.less'; import { Lecture } from '@/types/lecture'; -import { Row, Input, Space, Col } from 'antd'; +import { Row, Input, Typography, Col, Button } from 'antd'; import { useMutation } from '@tanstack/react-query'; import { useEffect, useState } from 'react'; import apiClient, { ServerErrorResponse, ServerResponse } from '@/http'; @@ -13,13 +13,18 @@ import { CATEGORY_LECTURE_LIST, EVENT_ERROR_RESPONSE, EVENT_GOTO_LECTURE, + EVENT_LOAD_MORE, EVENT_SEARCHED, } from '@/matomo/events'; const { Search } = Input; +const { Paragraph } = Typography; + const AUTO_UPDATE_INTERVAL = 10000; +const PAGINATE_AFTER = 25; + interface LectureResponse extends ServerResponse { data: Lecture[]; } @@ -34,7 +39,10 @@ export default function LectureList(props: LectureListProps) { const [firstLoad, setFirstLoad] = useState(true); const [lectureQuery, setLectureQuery] = useState(''); + const [lastQuery, setLastQuery] = useState(''); + const [lastCourseCode, setLastCourseCode] = useState(''); const [lectures, setLectures] = useState([]); + const [limit, setLimit] = useState(PAGINATE_AFTER); const { isLoading: isSearchingLectures, mutate: doLectureSearch } = useMutation( @@ -60,7 +68,16 @@ export default function LectureList(props: LectureListProps) { data: res.data, }; setLectures(result.data); + if ( + lectureQuery !== lastQuery || + lastCourseCode !== courseCode || + firstLoad + ) { + setLimit(Math.min(PAGINATE_AFTER, result.data.length)); + } setFirstLoad(false); + setLastQuery(lectureQuery); + setLastCourseCode(courseCode); }, onError: (err: ServerErrorResponse) => { console.log(err); @@ -79,6 +96,16 @@ export default function LectureList(props: LectureListProps) { emitEvent(CATEGORY_LECTURE_LIST, EVENT_SEARCHED, query); }; + const loadMore = () => { + if (limit + PAGINATE_AFTER > lectures.length) { + setLimit(lectures.length); + } else { + setLimit(limit + PAGINATE_AFTER); + } + + emitEvent(CATEGORY_LECTURE_LIST, EVENT_LOAD_MORE, ACTION_NONE); + }; + const goToLecture = async (lecture: Lecture, newTab = false) => { const url = `/lectures/${lecture.public_id}/${lecture.language}/questions`; @@ -96,6 +123,7 @@ export default function LectureList(props: LectureListProps) { }; useEffect(() => { + setFirstLoad(true); searchLectures(''); }, [courseCode]); // eslint-disable-line react-hooks/exhaustive-deps @@ -127,14 +155,17 @@ export default function LectureList(props: LectureListProps) { {isSearchingLectures && firstLoad && ( )} - +
{lectures.map((lecture, index) => { + if (index + 1 > limit) { + return
; + } + return ( - + {index + 1} @@ -149,7 +180,28 @@ export default function LectureList(props: LectureListProps) { ); })} - +
+ +
+ + + + + + + + Showing {limit} / {lectures.length} lectures + + +
); From 5f240313a94b1205b225b87d82b1ce70a3e389dc Mon Sep 17 00:00:00 2001 From: Ludwig Kristoffersson Date: Mon, 24 Apr 2023 22:51:12 +0200 Subject: [PATCH 3/5] hide the result container in the lecture-list on first load so it forces a scroll to the top when jumping between courses --- .../lecture/lecture-list/lecture-list.tsx | 113 +++++++++--------- 1 file changed, 59 insertions(+), 54 deletions(-) diff --git a/web-ui/src/components/lecture/lecture-list/lecture-list.tsx b/web-ui/src/components/lecture/lecture-list/lecture-list.tsx index cd8b242..c6d59c0 100644 --- a/web-ui/src/components/lecture/lecture-list/lecture-list.tsx +++ b/web-ui/src/components/lecture/lecture-list/lecture-list.tsx @@ -123,9 +123,12 @@ export default function LectureList(props: LectureListProps) { }; useEffect(() => { - setFirstLoad(true); searchLectures(''); - }, [courseCode]); // eslint-disable-line react-hooks/exhaustive-deps + + if (courseCode !== lastCourseCode) { + setFirstLoad(true); + } + }, [courseCode, lastCourseCode]); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { const interval = setInterval(() => { @@ -151,58 +154,60 @@ export default function LectureList(props: LectureListProps) { /> - - {isSearchingLectures && firstLoad && ( - - )} -
- {lectures.map((lecture, index) => { - if (index + 1 > limit) { - return
; - } - - return ( - - - {index + 1} - - - goToLecture(lecture)} - onMetaClick={() => goToLecture(lecture, true)} - onCtrlClick={() => goToLecture(lecture, true)} - /> - - - ); - })} -
- -
- - - - - - - - Showing {limit} / {lectures.length} lectures - - -
-
+ {!firstLoad && ( + + {isSearchingLectures && firstLoad && ( + + )} +
+ {lectures.map((lecture, index) => { + if (index + 1 > limit) { + return
; + } + + return ( + + + {index + 1} + + + goToLecture(lecture)} + onMetaClick={() => goToLecture(lecture, true)} + onCtrlClick={() => goToLecture(lecture, true)} + /> + + + ); + })} +
+ +
+ + + + + + + + Showing {limit} / {lectures.length} lectures + + +
+
+ )} ); } From 5c200517f8c8e8d4cac473bc36c8c1238a1c03e3 Mon Sep 17 00:00:00 2001 From: Ludwig Kristoffersson Date: Mon, 24 Apr 2023 23:18:37 +0200 Subject: [PATCH 4/5] add compact mode to image upload --- .../image/image-upload/image-upload.less | 14 ++++++++++ .../image/image-upload/image-upload.tsx | 26 ++++++++++++++----- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/web-ui/src/components/image/image-upload/image-upload.less b/web-ui/src/components/image/image-upload/image-upload.less index d140654..d8f619b 100644 --- a/web-ui/src/components/image/image-upload/image-upload.less +++ b/web-ui/src/components/image/image-upload/image-upload.less @@ -12,6 +12,20 @@ margin: 0; } + &.compact { + > div:first-child { + height: 150px; + padding: 0px 20px; + } + + *.icon { + text-align: center; + font-size: 30px; + margin-top: 10px; + margin-bottom: 10px; + } + } + > div:first-child { padding: 32px 10px; height: 300px; diff --git a/web-ui/src/components/image/image-upload/image-upload.tsx b/web-ui/src/components/image/image-upload/image-upload.tsx index 942ca74..4a27dbe 100644 --- a/web-ui/src/components/image/image-upload/image-upload.tsx +++ b/web-ui/src/components/image/image-upload/image-upload.tsx @@ -29,11 +29,12 @@ interface ImageResponse extends ServerResponse { interface ImageUploadProps { uploadId?: string; noMargin?: boolean; + compact?: boolean; onUploadComplete: (image: ImageType) => void; } export default function ImageUpload(props: ImageUploadProps) { - const { uploadId, onUploadComplete, noMargin } = props; + const { uploadId, onUploadComplete, noMargin, compact } = props; const [id, setId] = useState(null); const [error, setError] = useState(''); @@ -111,7 +112,9 @@ export default function ImageUpload(props: ImageUploadProps) { {contextHolder} {(id === null || image === null) && ( @@ -124,17 +127,26 @@ export default function ImageUpload(props: ImageUploadProps) { - Ask a question about an assignment + {(compact === undefined || compact === false) && ( + Ask a question about an assignment + )} + {compact === true && ( + + Ask a question about another assignment + + )} - - Click or drag an image of an assignment, lecture slide or lab - to this area to upload - + {(compact === undefined || compact === false) && ( + + Click or drag an image of an assignment, lecture slide or + lab to this area to upload + + )} )} From 481a389eb19b450876c9e5b05f27ce6523af5896 Mon Sep 17 00:00:00 2001 From: Ludwig Kristoffersson Date: Mon, 24 Apr 2023 23:19:40 +0200 Subject: [PATCH 5/5] add proper full preview of current assigment --- web-ui/src/pages/assignments/index.less | 8 ++++++++ web-ui/src/pages/assignments/index.tsx | 18 ++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/web-ui/src/pages/assignments/index.less b/web-ui/src/pages/assignments/index.less index c35c87a..900c272 100644 --- a/web-ui/src/pages/assignments/index.less +++ b/web-ui/src/pages/assignments/index.less @@ -11,3 +11,11 @@ .full_width { width: 100%; } + +.image_preview { + width: 100%; + border: 2px dashed #d9d9d9; + border-radius: 8px; + padding: 10px; + overflow: hidden; +} diff --git a/web-ui/src/pages/assignments/index.tsx b/web-ui/src/pages/assignments/index.tsx index 9ef8cd5..54dc24e 100644 --- a/web-ui/src/pages/assignments/index.tsx +++ b/web-ui/src/pages/assignments/index.tsx @@ -10,11 +10,16 @@ import { Space, Typography, notification, + Image as AntImage, } from 'antd'; import { useMutation } from '@tanstack/react-query'; import { useEffect, useState } from 'react'; import { useParams } from 'umi'; -import apiClient, { ServerErrorResponse, ServerResponse } from '@/http'; +import apiClient, { + ServerErrorResponse, + ServerResponse, + makeUrl, +} from '@/http'; import { Image } from '@/types/search'; import ImageUpload from '@/components/image/image-upload/image-upload'; import ImageProgress from '@/components/image/image-progress/image-progress'; @@ -99,6 +104,8 @@ export default function AssignmentsIndexPage() { fetchImage(); }; + const previewUrl = makeUrl(`/assignments/image/${id}/img`); + useEffect(() => { registerPageLoad(); }, []); @@ -174,10 +181,17 @@ export default function AssignmentsIndexPage() { + + + onImageUploadComplete(image)} />