From a5f7ee12552aa36022c09e6ccfa9a9f8e1449fb8 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:37:03 +0200 Subject: [PATCH 01/18] FE: Limiting author name length --- frontend/.env.example | 3 ++- .../src/components/questionpreview/QuestionPreview.tsx | 2 +- frontend/src/pages/dashboard/question/QuestionView.tsx | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/frontend/.env.example b/frontend/.env.example index 40e5294d..5705a99f 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1 +1,2 @@ -VITE_BACKEND_URL=http://localhost:3000/ \ No newline at end of file +VITE_BACKEND_URL=http://localhost:3000/ +VITE_AUTHOR_NAME_MAX_LENGTH=12 diff --git a/frontend/src/components/questionpreview/QuestionPreview.tsx b/frontend/src/components/questionpreview/QuestionPreview.tsx index 86331294..578ed1a4 100644 --- a/frontend/src/components/questionpreview/QuestionPreview.tsx +++ b/frontend/src/components/questionpreview/QuestionPreview.tsx @@ -99,7 +99,7 @@ export default function QuestionPreview(props: Props) { {

Asked by - { props.question.author.name } + { props.question.author.name.substring(0, import.meta.env.VITE_AUTHOR_NAME_MAX_LENGTH) }

diff --git a/frontend/src/pages/dashboard/question/QuestionView.tsx b/frontend/src/pages/dashboard/question/QuestionView.tsx index 61dc3edd..b049da02 100644 --- a/frontend/src/pages/dashboard/question/QuestionView.tsx +++ b/frontend/src/pages/dashboard/question/QuestionView.tsx @@ -248,8 +248,12 @@ export default function QuestionView() {

{ question ? <> - { question.author.name } - { question.author.type.toUpperCase() } + + { question.author.name.substring(0, import.meta.env.VITE_AUTHOR_NAME_MAX_LENGTH) } + + + { question.author.type !== "user" && + { question.author.type.toUpperCase() }} : }

From b6016afae22d596646ccd40298041b2af432318a Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:39:12 +0200 Subject: [PATCH 02/18] FE: Implementing Active Question Title Display --- frontend/src/pages/dashboard/Dashboard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/dashboard/Dashboard.tsx b/frontend/src/pages/dashboard/Dashboard.tsx index 5900e40b..b0449a5e 100644 --- a/frontend/src/pages/dashboard/Dashboard.tsx +++ b/frontend/src/pages/dashboard/Dashboard.tsx @@ -56,7 +56,7 @@ export default function Dashboard(props: Props) { if (window.location.pathname.includes("/question")) { let questionId = window.location.pathname.split("/question/")[1].substring(0, 36); global.axios.get("question/" + questionId + "/title") - .then(res => console.log(res)) + .then(res => setActiveQuestionName(res.data.title)) .catch(err => axiosError(err, alert)); } } From 3b2c58b20598f6eb32ea036431cd195530aab345 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:39:26 +0200 Subject: [PATCH 03/18] FE: Disable browser auto-launch --- frontend/vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index da1425af..5bdaed1d 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -21,7 +21,7 @@ export default defineConfig(() => { }, server: { port: 3006, - open: true + open: false } }; }); From e255f2a0bce043aefc2b5dbd63653e798d85aa5f Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:39:52 +0200 Subject: [PATCH 04/18] FE: Enabling Question Creation --- frontend/src/pages/dashboard/editor/Editor.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/pages/dashboard/editor/Editor.tsx b/frontend/src/pages/dashboard/editor/Editor.tsx index 49d1b43e..89bdc50e 100644 --- a/frontend/src/pages/dashboard/editor/Editor.tsx +++ b/frontend/src/pages/dashboard/editor/Editor.tsx @@ -195,6 +195,8 @@ export default function Editor(props: {}) { tags: tags, content: description, useAI: questionType === "simp" + }, { + withCredentials: true }) .then(res => { alert.info(res.status); From d08c05dd35bcb3a116251122ea878e4bd43f61b0 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:40:11 +0200 Subject: [PATCH 05/18] FE: Updating Question author types --- frontend/src/def/Question.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/def/Question.d.ts b/frontend/src/def/Question.d.ts index a59395c8..156c9520 100644 --- a/frontend/src/def/Question.d.ts +++ b/frontend/src/def/Question.d.ts @@ -26,5 +26,5 @@ export interface Answer { interface Author { id: string; name: string; - type: "user" | "pro" | "ai"; + type: "guest" | "user" | "pro" | "admin" | "ai"; } From e14569bf635b9c03438aece6e9a40cc29ff223c7 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:40:35 +0200 Subject: [PATCH 06/18] FE: Fixing rating / opinion fetch --- frontend/src/pages/dashboard/question/QuestionView.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/dashboard/question/QuestionView.tsx b/frontend/src/pages/dashboard/question/QuestionView.tsx index b049da02..a6139aff 100644 --- a/frontend/src/pages/dashboard/question/QuestionView.tsx +++ b/frontend/src/pages/dashboard/question/QuestionView.tsx @@ -43,7 +43,7 @@ export default function QuestionView() { id: id ?? "", isDiscussion: res.data.isDiscussion ?? false, likes: res.data.likes ?? 0, - rating: res.data.rating ?? "none", + rating: res.data.opinion ?? "none", tags: res.data.tags ?? [], title: res.data.title ?? "", updated: formatDate(res.data.updated ?? "") @@ -272,7 +272,7 @@ export default function QuestionView() {
+ className={ "question-stat" + (question.rating === "like" ? " rating" : "") }> { question.likes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } @@ -280,7 +280,7 @@ export default function QuestionView() {
+ className={ "question-stat" + (question.rating === "dislike" ? " rating" : "") }> { question.dislikes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } From 6a20ea893b5dac759b365ebae60a2c577091ccb5 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:42:44 +0200 Subject: [PATCH 07/18] FE: Renaming rating to opinion --- .../src/components/questionpreview/QuestionPreview.tsx | 4 ++-- frontend/src/def/Question.d.ts | 4 ++-- frontend/src/pages/dashboard/question/QuestionView.tsx | 10 +++++----- frontend/src/pages/dashboard/trending/Trending.tsx | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/questionpreview/QuestionPreview.tsx b/frontend/src/components/questionpreview/QuestionPreview.tsx index 578ed1a4..618c40ed 100644 --- a/frontend/src/components/questionpreview/QuestionPreview.tsx +++ b/frontend/src/components/questionpreview/QuestionPreview.tsx @@ -63,7 +63,7 @@ export default function QuestionPreview(props: Props) {
+ className={ "question-stat" + (props.question.opinion === "like" ? " rating" : "") }> { props.question.likes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } @@ -71,7 +71,7 @@ export default function QuestionPreview(props: Props) {
+ className={ "question-stat" + (props.question.opinion === "dislike" ? " rating" : "") }> { props.question.dislikes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } diff --git a/frontend/src/def/Question.d.ts b/frontend/src/def/Question.d.ts index 156c9520..136bfd63 100644 --- a/frontend/src/def/Question.d.ts +++ b/frontend/src/def/Question.d.ts @@ -6,7 +6,7 @@ export interface Question { tags: string[]; likes: number; dislikes: number; - rating: "like" | "dislike" | "none"; + opinion: "like" | "dislike" | "none"; answers: number; created: string; updated: string; @@ -19,7 +19,7 @@ export interface Answer { created: string; likes: number; dislikes: number; - rating: "like" | "dislike" | "none"; + opinion: "like" | "dislike" | "none"; author: Author; } diff --git a/frontend/src/pages/dashboard/question/QuestionView.tsx b/frontend/src/pages/dashboard/question/QuestionView.tsx index a6139aff..5a130e1c 100644 --- a/frontend/src/pages/dashboard/question/QuestionView.tsx +++ b/frontend/src/pages/dashboard/question/QuestionView.tsx @@ -43,7 +43,7 @@ export default function QuestionView() { id: id ?? "", isDiscussion: res.data.isDiscussion ?? false, likes: res.data.likes ?? 0, - rating: res.data.opinion ?? "none", + opinion: res.data.opinion ?? "none", tags: res.data.tags ?? [], title: res.data.title ?? "", updated: formatDate(res.data.updated ?? "") @@ -122,14 +122,14 @@ export default function QuestionView() {
+ className={ "question-answer-actions-rate" + (answer.opinion === "like" ? " rating" : "") }> { answer.likes } likes
+ className={ "question-answer-actions-rate" + (answer.opinion === "dislike" ? " rating" : "") }> { answer.dislikes } dislikes @@ -272,7 +272,7 @@ export default function QuestionView() {
+ className={ "question-stat" + (question.opinion === "like" ? " rating" : "") }> { question.likes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } @@ -280,7 +280,7 @@ export default function QuestionView() {
+ className={ "question-stat" + (question.opinion === "dislike" ? " rating" : "") }> { question.dislikes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } diff --git a/frontend/src/pages/dashboard/trending/Trending.tsx b/frontend/src/pages/dashboard/trending/Trending.tsx index 96764404..773ec2a9 100644 --- a/frontend/src/pages/dashboard/trending/Trending.tsx +++ b/frontend/src/pages/dashboard/trending/Trending.tsx @@ -38,7 +38,7 @@ export default function Trending(props: {}) { id: _question.id, isDiscussion: _question.isDiscussion ?? false, likes: _question.likes ?? 0, - rating: _question.rating ?? "none", + opinion: _question.opinion ?? "none", tags: _question.tags ?? [], title: _question.title ?? "", updated: formatDate(_question.updated ?? "") From 7da207937d68e0157f725c93964e3eda64d7bde9 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:47:39 +0200 Subject: [PATCH 08/18] FE: Extracting QuestionStats from QuestionView --- .../dashboard/question/QuestionStats.tsx | 47 +++++++++++++++++++ .../pages/dashboard/question/QuestionView.tsx | 41 +--------------- 2 files changed, 49 insertions(+), 39 deletions(-) create mode 100644 frontend/src/pages/dashboard/question/QuestionStats.tsx diff --git a/frontend/src/pages/dashboard/question/QuestionStats.tsx b/frontend/src/pages/dashboard/question/QuestionStats.tsx new file mode 100644 index 00000000..ef5d3c61 --- /dev/null +++ b/frontend/src/pages/dashboard/question/QuestionStats.tsx @@ -0,0 +1,47 @@ +import Skeleton from "react-loading-skeleton"; +import React from "react"; +import { Question } from "../../../def/Question"; + +export default function QuestionStats(props: {question?: Question}) { + return <> + Question Stats +
+ { props.question ? <> +
+ + { "0".replace(/\B(?=(\d{3})+(?!\d))/g, ",") } + views +
+ +
+ + { props.question.likes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } + likes +
+ +
+ + { props.question.dislikes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } + dislikes +
+ +
+ + { props.question.answers.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } + answers +
+ : <> + + + + + } +
+ +} diff --git a/frontend/src/pages/dashboard/question/QuestionView.tsx b/frontend/src/pages/dashboard/question/QuestionView.tsx index 5a130e1c..58ee2534 100644 --- a/frontend/src/pages/dashboard/question/QuestionView.tsx +++ b/frontend/src/pages/dashboard/question/QuestionView.tsx @@ -12,6 +12,7 @@ import { formatDate } from "../../../def/converter"; import { useAlert } from "react-alert"; import { axiosError } from "../../../def/axios-error"; import NoContent from "../../../components/NoContent"; +import QuestionStats from "./QuestionStats"; /** * Renders the question page @@ -261,45 +262,7 @@ export default function QuestionView() {
- Question Stats -
- { question ? <> -
- - { "0".replace(/\B(?=(\d{3})+(?!\d))/g, ",") } - views -
- -
- - { question.likes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } - likes -
- -
- - { question.dislikes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } - dislikes -
- -
- - { question.answers.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } - answers -
- : <> - - - - - } -
+
From a2b1b39c8419b7121d86a934d492f6465623c4f3 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 09:47:49 +0200 Subject: [PATCH 09/18] FE: Adding a space --- frontend/src/pages/dashboard/question/QuestionView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/dashboard/question/QuestionView.tsx b/frontend/src/pages/dashboard/question/QuestionView.tsx index 58ee2534..877fffde 100644 --- a/frontend/src/pages/dashboard/question/QuestionView.tsx +++ b/frontend/src/pages/dashboard/question/QuestionView.tsx @@ -254,7 +254,7 @@ export default function QuestionView() { { question.author.type !== "user" && - { question.author.type.toUpperCase() }} + { question.author.type.toUpperCase() } } : }

From 67b2c64331b54299f78b0df92145afaf9161da18 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 10:01:11 +0200 Subject: [PATCH 10/18] FE: Adding count to QuestionPreviewSkeleton --- .../QuestionPreviewSkeleton.tsx | 73 ++++++++++--------- .../src/pages/dashboard/trending/Trending.tsx | 6 +- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/frontend/src/components/questionpreview/QuestionPreviewSkeleton.tsx b/frontend/src/components/questionpreview/QuestionPreviewSkeleton.tsx index 23a6fb81..bd1a6001 100644 --- a/frontend/src/components/questionpreview/QuestionPreviewSkeleton.tsx +++ b/frontend/src/components/questionpreview/QuestionPreviewSkeleton.tsx @@ -5,47 +5,52 @@ import React from "react"; /** * Renders a skeleton, based on QuestionPreview */ -export default function QuestionPreviewSkeleton() { - return
-
- - -

- -

- - -
- -
-
-
- -
+export default function QuestionPreviewSkeleton(props: { count?: number }) { + const { count = 1 } = props; + const skeletonArray = Array.from({ length: count }); + + return skeletonArray.map((_, i) => { + return
+
+ -
- -
+

+ +

+ +
-
-
- +
+
+
+ +
+ +
+ +
-
- +
+
+ +
+ +
+ +
-
- -
- -

- - -

+
+ + +

+ + +

+
-
+ }) } diff --git a/frontend/src/pages/dashboard/trending/Trending.tsx b/frontend/src/pages/dashboard/trending/Trending.tsx index 773ec2a9..9db356b3 100644 --- a/frontend/src/pages/dashboard/trending/Trending.tsx +++ b/frontend/src/pages/dashboard/trending/Trending.tsx @@ -126,11 +126,7 @@ export default function Trending(props: {}) { ? questions.map((question, index) => ) : - : <> - - - - + : } ; } From 35cfadae39668f8482c28a35ed9b49683a4b593a Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 10:01:39 +0200 Subject: [PATCH 11/18] FE: Extracting QuestionAnswerSkeleton from QuestionView --- .../question/QuestionAnswerSkeleton.tsx | 38 +++++++++++++++++++ .../pages/dashboard/question/QuestionView.tsx | 37 +----------------- 2 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 frontend/src/pages/dashboard/question/QuestionAnswerSkeleton.tsx diff --git a/frontend/src/pages/dashboard/question/QuestionAnswerSkeleton.tsx b/frontend/src/pages/dashboard/question/QuestionAnswerSkeleton.tsx new file mode 100644 index 00000000..a57cdd94 --- /dev/null +++ b/frontend/src/pages/dashboard/question/QuestionAnswerSkeleton.tsx @@ -0,0 +1,38 @@ +import Skeleton from "react-loading-skeleton"; +import React from "react"; + +export default function QuestionAnswerSkeleton(props: { count?: number }) { + const { count = 1 } = props; + const skeletonArray = Array.from({ length: count }); + + return skeletonArray.map((_, i) => { + return
+
+ + +

+ +

+ + +
+ +
+
+

+ +

+
+ +
+ + + +
+ + +
+
+
+ }) +} diff --git a/frontend/src/pages/dashboard/question/QuestionView.tsx b/frontend/src/pages/dashboard/question/QuestionView.tsx index 877fffde..38fd99a8 100644 --- a/frontend/src/pages/dashboard/question/QuestionView.tsx +++ b/frontend/src/pages/dashboard/question/QuestionView.tsx @@ -13,6 +13,7 @@ import { useAlert } from "react-alert"; import { axiosError } from "../../../def/axios-error"; import NoContent from "../../../components/NoContent"; import QuestionStats from "./QuestionStats"; +import QuestionAnswerSkeleton from "./QuestionAnswerSkeleton"; /** * Renders the question page @@ -147,37 +148,6 @@ export default function QuestionView() {
} - const renderAnswerSkeleton = () => { - return
-
- - -

- -

- - -
- -
-
-

- -

-
- -
- - - -
- - -
-
-
- } - return
@@ -212,10 +182,7 @@ export default function QuestionView() { ? answers.length > 0 ? answers.map((answer, index) => renderAnswer(answer, index)) : - : <> - { renderAnswerSkeleton() } - { renderAnswerSkeleton() } - } + : }
Date: Thu, 6 Jun 2024 10:04:24 +0200 Subject: [PATCH 12/18] FE: Extracting QuestionAnswer from QuestionView --- .../questionpreview/QuestionAnswer.tsx | 64 ++++++++++++++++++ .../pages/dashboard/question/QuestionView.tsx | 65 +------------------ 2 files changed, 66 insertions(+), 63 deletions(-) create mode 100644 frontend/src/components/questionpreview/QuestionAnswer.tsx diff --git a/frontend/src/components/questionpreview/QuestionAnswer.tsx b/frontend/src/components/questionpreview/QuestionAnswer.tsx new file mode 100644 index 00000000..82e97aea --- /dev/null +++ b/frontend/src/components/questionpreview/QuestionAnswer.tsx @@ -0,0 +1,64 @@ +import { Answer } from "../../def/Question"; +import React from "react"; + +export default function QuestionAnswer(props: { answer: Answer, index: number }) { + return
+
+ { props.answer.author.type === "ai" ? <> + + +

+ Simp +

+ :
+ { + +

+ { props.answer.author.name } + { props.answer.author.type.toUpperCase() } +

+
} + + replied { props.answer.created } +
+ +
+
+

{ props.answer.content }

+
+ +
+
+ + { props.answer.likes } + likes +
+ +
+ + { props.answer.dislikes } + dislikes +
+ +
+ + +
+
+
+} diff --git a/frontend/src/pages/dashboard/question/QuestionView.tsx b/frontend/src/pages/dashboard/question/QuestionView.tsx index 38fd99a8..d14b787d 100644 --- a/frontend/src/pages/dashboard/question/QuestionView.tsx +++ b/frontend/src/pages/dashboard/question/QuestionView.tsx @@ -14,6 +14,7 @@ import { axiosError } from "../../../def/axios-error"; import NoContent from "../../../components/NoContent"; import QuestionStats from "./QuestionStats"; import QuestionAnswerSkeleton from "./QuestionAnswerSkeleton"; +import QuestionAnswer from "../../../components/questionpreview/QuestionAnswer"; /** * Renders the question page @@ -86,68 +87,6 @@ export default function QuestionView() { } } - const renderAnswer = (answer: Answer, index: number) => { - return
-
- { answer.author.type === "ai" ? <> - - -

- Simp -

- :
- { - -

- { answer.author.name } - { answer.author.type.toUpperCase() } -

-
} - - replied { answer.created } -
- -
-
-

{ answer.content }

-
- -
-
- - { answer.likes } - likes -
- -
- - { answer.dislikes } - dislikes -
- -
- - -
-
-
- } - return
@@ -180,7 +119,7 @@ export default function QuestionView() { { !answersLoading ? answers.length > 0 - ? answers.map((answer, index) => renderAnswer(answer, index)) + ? answers.map((answer, index) => ) : : } From 43c5f4a80edd536ce92d67374ce1a1ec0eafec4c Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Thu, 6 Jun 2024 10:05:56 +0200 Subject: [PATCH 13/18] FE: Updating Comments --- frontend/src/components/questionpreview/QuestionAnswer.tsx | 4 ++++ .../src/pages/dashboard/question/QuestionAnswerSkeleton.tsx | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/frontend/src/components/questionpreview/QuestionAnswer.tsx b/frontend/src/components/questionpreview/QuestionAnswer.tsx index 82e97aea..2c7a232c 100644 --- a/frontend/src/components/questionpreview/QuestionAnswer.tsx +++ b/frontend/src/components/questionpreview/QuestionAnswer.tsx @@ -1,6 +1,10 @@ import { Answer } from "../../def/Question"; import React from "react"; +/** + * Renders an answer to be displayed in QuestionView + * @param props holds the answer and an index + */ export default function QuestionAnswer(props: { answer: Answer, index: number }) { return
Date: Thu, 6 Jun 2024 10:36:10 +0200 Subject: [PATCH 14/18] FE: Creating Avatar Component --- frontend/src/components/avatar/Avatar.scss | 8 ++++++++ frontend/src/components/avatar/Avatar.tsx | 12 ++++++++++++ .../components/questionpreview/QuestionAnswer.tsx | 3 ++- .../components/questionpreview/QuestionPreview.tsx | 3 ++- frontend/src/index.scss | 9 --------- frontend/src/pages/dashboard/Dashboard.tsx | 9 ++------- .../src/pages/dashboard/question/QuestionView.tsx | 3 ++- 7 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 frontend/src/components/avatar/Avatar.scss create mode 100644 frontend/src/components/avatar/Avatar.tsx diff --git a/frontend/src/components/avatar/Avatar.scss b/frontend/src/components/avatar/Avatar.scss new file mode 100644 index 00000000..c87b1b74 --- /dev/null +++ b/frontend/src/components/avatar/Avatar.scss @@ -0,0 +1,8 @@ +.avatar { + border-radius: 50%; + filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5)); + height: 40px !important; + object-fit: cover; + pointer-events: none; + width: 40px !important; +} diff --git a/frontend/src/components/avatar/Avatar.tsx b/frontend/src/components/avatar/Avatar.tsx new file mode 100644 index 00000000..96647770 --- /dev/null +++ b/frontend/src/components/avatar/Avatar.tsx @@ -0,0 +1,12 @@ +import "./Avatar.scss"; +import React from "react"; + +export default function Avatar(props: { userId?: string }) { + return { { + currentTarget.onerror = null; // prevents looping + currentTarget.src = "https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50"; + } }/> +} diff --git a/frontend/src/components/questionpreview/QuestionAnswer.tsx b/frontend/src/components/questionpreview/QuestionAnswer.tsx index 2c7a232c..66291202 100644 --- a/frontend/src/components/questionpreview/QuestionAnswer.tsx +++ b/frontend/src/components/questionpreview/QuestionAnswer.tsx @@ -1,5 +1,6 @@ import { Answer } from "../../def/Question"; import React from "react"; +import Avatar from "../avatar/Avatar"; /** * Renders an answer to be displayed in QuestionView @@ -25,7 +26,7 @@ export default function QuestionAnswer(props: { answer: Answer, index: number }) Simp

:
- { +

{ props.answer.author.name } diff --git a/frontend/src/components/questionpreview/QuestionPreview.tsx b/frontend/src/components/questionpreview/QuestionPreview.tsx index 618c40ed..0ef13421 100644 --- a/frontend/src/components/questionpreview/QuestionPreview.tsx +++ b/frontend/src/components/questionpreview/QuestionPreview.tsx @@ -2,6 +2,7 @@ import "./QuestionPreview.scss"; import React from "react"; import { useNavigate } from "react-router-dom"; import { Question } from "../../def/Question"; +import Avatar from "../avatar/Avatar"; interface Props { question: Question; @@ -96,7 +97,7 @@ export default function QuestionPreview(props: Props) {

- { +

Asked by { props.question.author.name.substring(0, import.meta.env.VITE_AUTHOR_NAME_MAX_LENGTH) } diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 8f153808..0316a0b1 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -95,15 +95,6 @@ code { } } -.avatar { - border-radius: 50%; - filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5)); - height: 40px !important; - object-fit: cover; - pointer-events: none; - width: 40px !important; -} - ::selection { background-color: var(--primary-color); color: var(--primary-color-contrast); diff --git a/frontend/src/pages/dashboard/Dashboard.tsx b/frontend/src/pages/dashboard/Dashboard.tsx index b0449a5e..6c3d37bd 100644 --- a/frontend/src/pages/dashboard/Dashboard.tsx +++ b/frontend/src/pages/dashboard/Dashboard.tsx @@ -14,6 +14,7 @@ import Skeleton from "react-loading-skeleton"; import Search from "../../components/search/Search"; import { axiosError } from "../../def/axios-error"; import { useAlert } from "react-alert"; +import Avatar from "../../components/avatar/Avatar"; // ory setup const basePath = "http://localhost:4000" @@ -168,13 +169,7 @@ export default function Dashboard(props: Props) { boxShadow: "var(--box-shadow)" } } tabIndex={ 0 }> - { { - currentTarget.onerror = null; // prevents looping - currentTarget.src = "https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50"; - } }/> +

} items={ [ { diff --git a/frontend/src/pages/dashboard/question/QuestionView.tsx b/frontend/src/pages/dashboard/question/QuestionView.tsx index d14b787d..133ea8db 100644 --- a/frontend/src/pages/dashboard/question/QuestionView.tsx +++ b/frontend/src/pages/dashboard/question/QuestionView.tsx @@ -15,6 +15,7 @@ import NoContent from "../../../components/NoContent"; import QuestionStats from "./QuestionStats"; import QuestionAnswerSkeleton from "./QuestionAnswerSkeleton"; import QuestionAnswer from "../../../components/questionpreview/QuestionAnswer"; +import Avatar from "../../../components/avatar/Avatar"; /** * Renders the question page @@ -147,7 +148,7 @@ export default function QuestionView() {
{ question - ? { + ? : }
From fb6f151b38a0910ff7930c9f5e0f3a3563a30a21 Mon Sep 17 00:00:00 2001 From: Benjamin Loidl Date: Fri, 7 Jun 2024 00:23:46 +0200 Subject: [PATCH 15/18] FE: Making Buttons look way cooler! And fixing some styling issues --- frontend/src/components/button/Button.scss | 4 -- frontend/src/components/button/Button.tsx | 11 +++- .../src/components/dropdown/Dropdown.scss | 7 +-- frontend/src/components/dropdown/Dropdown.tsx | 7 ++- frontend/src/def/cool-blobs.ts | 30 ++++++++++ frontend/src/index.scss | 20 +++++++ frontend/src/pages/dashboard/Dashboard.scss | 2 +- frontend/src/pages/dashboard/Dashboard.tsx | 58 ++++++++++++------- frontend/src/pages/home/Home.tsx | 6 +- frontend/src/pages/home/Login.scss | 2 +- frontend/src/pages/home/Login.tsx | 13 ++--- 11 files changed, 112 insertions(+), 48 deletions(-) create mode 100644 frontend/src/def/cool-blobs.ts diff --git a/frontend/src/components/button/Button.scss b/frontend/src/components/button/Button.scss index e13ffa54..6de3423f 100644 --- a/frontend/src/components/button/Button.scss +++ b/frontend/src/components/button/Button.scss @@ -23,10 +23,6 @@ overflow: hidden; position: relative; - * { - z-index: 10; - } - &::before { animation: rotate 2s infinite linear; background-color: transparent; diff --git a/frontend/src/components/button/Button.tsx b/frontend/src/components/button/Button.tsx index 11121e79..7e2257dd 100644 --- a/frontend/src/components/button/Button.tsx +++ b/frontend/src/components/button/Button.tsx @@ -1,5 +1,6 @@ import React from "react"; import "./Button.scss"; +import { animateBlob } from "../../def/cool-blobs"; interface Props { buttonStyle?: "primary" | "glass", @@ -7,7 +8,8 @@ interface Props { onClick?: () => Promise, children?: React.ReactNode, disabled?: boolean, - placeIconRight?: boolean + placeIconRight?: boolean, + type?: "button" | "reset" | "submit" } /** @@ -24,8 +26,11 @@ export default function Button(props: Props) { return ( ); } diff --git a/frontend/src/components/dropdown/Dropdown.scss b/frontend/src/components/dropdown/Dropdown.scss index d0ae8a2e..8dd26581 100644 --- a/frontend/src/components/dropdown/Dropdown.scss +++ b/frontend/src/components/dropdown/Dropdown.scss @@ -98,6 +98,7 @@ border: none; cursor: pointer; display: flex; + gap: var(--spacing); padding: var(--spacing); width: 100%; @@ -113,18 +114,12 @@ } > i:first-child { - margin-inline-end: var(--spacing); text-align: center; width: 20px; } - > i:last-child { - margin-inline-start: var(--spacing); - } - > span:first-of-type { flex: 1; - padding-inline-end: calc(var(--spacing) * 2); } .shortcut { diff --git a/frontend/src/components/dropdown/Dropdown.tsx b/frontend/src/components/dropdown/Dropdown.tsx index 97c93fcb..88b9799f 100644 --- a/frontend/src/components/dropdown/Dropdown.tsx +++ b/frontend/src/components/dropdown/Dropdown.tsx @@ -1,5 +1,6 @@ import React from "react"; import "./Dropdown.scss"; +import { animateBlob } from "../../def/cool-blobs"; interface Item { label: string, @@ -60,7 +61,9 @@ export default function Dropdown(props: { { item.header &&
{ item.header }
} { item.expanded && item.items && item.items.length > 0 && renderItems(item.items, level + 1, diff --git a/frontend/src/def/cool-blobs.ts b/frontend/src/def/cool-blobs.ts new file mode 100644 index 00000000..df087753 --- /dev/null +++ b/frontend/src/def/cool-blobs.ts @@ -0,0 +1,30 @@ +import React from "react"; + +export const animateBlob = (e: React.MouseEvent) => { + const _blob = e.currentTarget.querySelector("span.button-blob"); + if (!_blob) return; + let blob = _blob as HTMLElement; + + let buttonRect = e.currentTarget.getBoundingClientRect(); + let docEl = document.documentElement; + let left = buttonRect.left + (window.pageXOffset || docEl.scrollLeft || 0); + + let x = e.clientX - left; + + const fromLeftLimit = 30; + const fromRightLimit = (buttonRect.width - fromLeftLimit); + let fromX = x < fromLeftLimit ? fromLeftLimit : x > fromRightLimit ? fromRightLimit : x; + + const toLeftLimit = 60; + const toRightLimit = (buttonRect.width - toLeftLimit); + let toX = x < toLeftLimit ? toLeftLimit : x > toRightLimit ? toRightLimit : x; + + blob.animate([ + { opacity: 1, width: "60px", height: "80%", top: "10%", transform: "translateX(calc(" + fromX + "px - 50%))" }, + { opacity: 0, width: "120px", height: "100%", top: 0, transform: "translateX(calc(" + toX + "px - 50%))" } + ], { + duration: 400, + fill: "forwards", + easing: "ease" + }); +} diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 0316a0b1..c0cb036c 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -250,3 +250,23 @@ hr { color: var(--primary-color-contrast); } } + +*:has(> span.button-blob) { + position: relative; + + * { + z-index: 10; + } + + span.button-blob { + position: absolute; + height: 100%; + width: 60px; + top: 0; + left: 0; + border-radius: var(--border-radius); + background: var(--border-color); + z-index: 1; + opacity: 0; + } +} diff --git a/frontend/src/pages/dashboard/Dashboard.scss b/frontend/src/pages/dashboard/Dashboard.scss index defc6a4e..e6550a17 100644 --- a/frontend/src/pages/dashboard/Dashboard.scss +++ b/frontend/src/pages/dashboard/Dashboard.scss @@ -30,7 +30,7 @@ justify-content: center; } - a { + a.navigate { align-items: center; border-radius: var(--border-radius) 0 0 var(--border-radius); color: inherit; diff --git a/frontend/src/pages/dashboard/Dashboard.tsx b/frontend/src/pages/dashboard/Dashboard.tsx index 6c3d37bd..3d7df36b 100644 --- a/frontend/src/pages/dashboard/Dashboard.tsx +++ b/frontend/src/pages/dashboard/Dashboard.tsx @@ -15,6 +15,7 @@ import Search from "../../components/search/Search"; import { axiosError } from "../../def/axios-error"; import { useAlert } from "react-alert"; import Avatar from "../../components/avatar/Avatar"; +import { animateBlob } from "../../def/cool-blobs"; // ory setup const basePath = "http://localhost:4000" @@ -256,14 +257,21 @@ export default function Dashboard(props: Props) { return