From 9fdb91bc80d0447272568a2cffdcc380ae9c5355 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 5 Sep 2024 11:08:46 +0200 Subject: [PATCH] Create new chip components to represent status and grade status --- .../frontend_apps/components/StatusChip.tsx | 33 +++++++++++++++ .../components/dashboard/GradeStatusChip.tsx | 42 +++++++++++++++++++ .../components/GradeStatusChipPage.tsx | 37 ++++++++++++++++ lms/static/scripts/ui-playground/index.ts | 10 ++++- 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 lms/static/scripts/frontend_apps/components/StatusChip.tsx create mode 100644 lms/static/scripts/frontend_apps/components/dashboard/GradeStatusChip.tsx create mode 100644 lms/static/scripts/ui-playground/components/GradeStatusChipPage.tsx diff --git a/lms/static/scripts/frontend_apps/components/StatusChip.tsx b/lms/static/scripts/frontend_apps/components/StatusChip.tsx new file mode 100644 index 0000000000..8fca7370b1 --- /dev/null +++ b/lms/static/scripts/frontend_apps/components/StatusChip.tsx @@ -0,0 +1,33 @@ +import classnames from 'classnames'; +import type { ComponentChildren } from 'preact'; + +export type StatusChipProps = { + /** + * Determines the aspect of the status chip, being "top" the one representing + * the most successful status, and "bottom" the one representing a total + * failure. + */ + variant: 'top' | 'high' | 'medium' | 'low' | 'bottom'; + + children?: ComponentChildren; +}; + +/** + * A status chip (AKA label or tag) that visually represents the success level + * on a scale of 1 to 5 + */ +export default function StatusChip({ variant, children }: StatusChipProps) { + return ( +
+ {children} +
+ ); +} diff --git a/lms/static/scripts/frontend_apps/components/dashboard/GradeStatusChip.tsx b/lms/static/scripts/frontend_apps/components/dashboard/GradeStatusChip.tsx new file mode 100644 index 0000000000..62efea77de --- /dev/null +++ b/lms/static/scripts/frontend_apps/components/dashboard/GradeStatusChip.tsx @@ -0,0 +1,42 @@ +import { useMemo } from 'preact/hooks'; + +import type { StatusChipProps } from '../StatusChip'; +import StatusChip from '../StatusChip'; + +export type GradeStatusChipProps = { + /** + * A grade, from 0 to 100, that will be used to render the corresponding + * StatusChip. + * + * 100 - top + * 80-99 - high + * 50-79 - medium + * 1-49 - low + * 0 - bottom + */ + grade: number; +}; + +/** + * A StatusChip where the corresponding variant is calculated from a grade + * from 0 to 100 + * + * See {@link StatusChip} + */ +export default function GradeStatusChip({ grade }: GradeStatusChipProps) { + const variant = useMemo((): StatusChipProps['variant'] => { + if (grade === 100) { + return 'top'; + } else if (grade >= 80 && grade < 100) { + return 'high'; + } else if (grade >= 50 && grade < 80) { + return 'medium'; + } else if (grade >= 1 && grade < 50) { + return 'low'; + } + + return 'bottom'; + }, [grade]); + + return {grade}%; +} diff --git a/lms/static/scripts/ui-playground/components/GradeStatusChipPage.tsx b/lms/static/scripts/ui-playground/components/GradeStatusChipPage.tsx new file mode 100644 index 0000000000..9199c13bbc --- /dev/null +++ b/lms/static/scripts/ui-playground/components/GradeStatusChipPage.tsx @@ -0,0 +1,37 @@ +import Library from '@hypothesis/frontend-shared/lib/pattern-library/components/Library'; + +import StatusChip from '../../frontend_apps/components/StatusChip'; +import GradeStatusChip from '../../frontend_apps/components/dashboard/GradeStatusChip'; + +export default function GradeStatusChipPage() { + return ( + + +

+ It can render any kind of content. The color can be customized via{' '} + variant prop. +

+ + Top + High + Medium + Low + Bottom + +
+ +

+ It renders a StatusChip by automatically calculating the + right variant, based on a grade from 0 to 100. +

+ + + + + + + +
+
+ ); +} diff --git a/lms/static/scripts/ui-playground/index.ts b/lms/static/scripts/ui-playground/index.ts index a0299e2895..6a3b1ae3c5 100644 --- a/lms/static/scripts/ui-playground/index.ts +++ b/lms/static/scripts/ui-playground/index.ts @@ -2,8 +2,16 @@ import { startApp } from '@hypothesis/frontend-shared/lib/pattern-library'; import type { CustomPlaygroundRoute } from '@hypothesis/frontend-shared/lib/pattern-library/routes'; +import GradeStatusChipPage from './components/GradeStatusChipPage'; + // LMS prototype pages should be defined here -const extraRoutes: CustomPlaygroundRoute[] = []; +const extraRoutes: CustomPlaygroundRoute[] = [ + { + component: GradeStatusChipPage, + route: '/grade-status-chip', + title: 'Grade status chip', + }, +]; startApp({ baseURL: '/ui-playground',