From c786a827ed98ac77e26ea7d52c162d0e36fbd088 Mon Sep 17 00:00:00 2001 From: Luca Pezzolla Date: Wed, 27 Mar 2024 18:14:30 +0100 Subject: [PATCH 1/2] refactor(agenda): improve lectures appearance in agenda Ref #371 --- lib/ui/components/AgendaCard.tsx | 111 ++++++++++++---- lib/ui/types/Theme.ts | 8 +- src/core/themes/dark.ts | 2 +- src/core/themes/light.ts | 8 +- src/features/agenda/components/AgendaTabs.tsx | 122 ------------------ .../agenda/components/AgendaTypeFilter.tsx | 30 ++--- .../agenda/components/BookingCard.tsx | 2 +- .../agenda/components/DeadlineCard.tsx | 2 +- src/features/agenda/components/ExamCard.tsx | 2 +- .../agenda/components/LectureCard.tsx | 30 +++-- 10 files changed, 134 insertions(+), 183 deletions(-) delete mode 100644 src/features/agenda/components/AgendaTabs.tsx diff --git a/lib/ui/components/AgendaCard.tsx b/lib/ui/components/AgendaCard.tsx index 8b553759..0226f831 100644 --- a/lib/ui/components/AgendaCard.tsx +++ b/lib/ui/components/AgendaCard.tsx @@ -1,8 +1,12 @@ -import { PropsWithChildren } from 'react'; -import { StyleSheet, TouchableHighlight, View } from 'react-native'; +import { PropsWithChildren, useMemo } from 'react'; +import { StyleSheet, TouchableHighlight, ViewProps } from 'react-native'; +import { isTablet as isTabletHelper } from 'react-native-device-info'; +import { faLocationDot } from '@fortawesome/free-solid-svg-icons'; import { Col } from '@lib/ui/components/Col'; +import { Icon } from '@lib/ui/components/Icon'; import { Row } from '@lib/ui/components/Row'; +import { Stack } from '@lib/ui/components/Stack'; import { useStylesheet } from '@lib/ui/hooks/useStylesheet'; import { useTheme } from '@lib/ui/hooks/useTheme'; import { Theme } from '@lib/ui/types/Theme'; @@ -20,7 +24,7 @@ export interface AgendaCardProps { /** * The color of the event type */ - color: string; + color?: string; /** * Extra information on this event */ @@ -58,6 +62,7 @@ export interface AgendaCardProps { * If true, the card will be compact */ isCompact?: boolean; + style?: ViewProps['style']; } /** @@ -75,9 +80,25 @@ export const AgendaCard = ({ type, location, onPress, + style, }: PropsWithChildren) => { const styles = useStylesheet(createStyles); - const { colors, spacing } = useTheme(); + const { colors, dark, palettes, shapes, spacing, fontSizes } = useTheme(); + + const isTablet = useMemo(() => isTabletHelper(), []); + const showsIcon = useMemo( + () => iconColor && (icon || isTablet), + [icon, iconColor, isTablet], + ); + + const secondaryIfLecture = useMemo( + () => + ['lezione', 'lecture'].includes(type.toLowerCase()) + ? { color: colors.lectureCardSecondary } + : undefined, + [type, colors.lectureCardSecondary], + ); + return ( - + + {/* Time and event type are only shown if the card is not compact */} {!isCompact && ( - - {time && time} - + + + + {time && time} + + {!isCompact && live && } + + {type} )} - - {iconColor && } + + + {showsIcon && } {title} - - {live && ( - - - - )} + + + {/* Extra children are only shown if the card is not compact */} {!isCompact && children} + {location && ( - - {location} - + + + + {location} + + )} @@ -149,10 +206,19 @@ const createStyles = ({ dark, }: Theme) => StyleSheet.create({ + titleContainer: { + flex: 1, + alignItems: 'center', + }, title: { flex: 1, fontWeight: fontWeights.semibold, fontSize: fontSizes.md, + lineHeight: fontSizes.md * 1.3, + }, + titleCompact: { + fontSize: fontSizes.xs, + lineHeight: fontSizes.xs * 1.3, }, titleWithIcon: { marginLeft: spacing[1.5], @@ -176,7 +242,4 @@ const createStyles = ({ fontWeight: fontWeights.semibold, marginTop: spacing[1.5], }, - location: { - marginTop: spacing[1.5], - }, }); diff --git a/lib/ui/types/Theme.ts b/lib/ui/types/Theme.ts index 045dc023..9caf8001 100644 --- a/lib/ui/types/Theme.ts +++ b/lib/ui/types/Theme.ts @@ -92,10 +92,10 @@ export interface Colors { tabBarInactive: string; title: string; touchableHighlight: string; - agendaBooking: string; - agendaDeadline: string; - agendaExam: string; - agendaLecture: string; + bookingCardBorder: string; + deadlineCardBorder: string; + examCardBorder: string; + lectureCardSecondary: string; translucentSurface: string; white: string; } diff --git a/src/core/themes/dark.ts b/src/core/themes/dark.ts index 34effe9c..5555ac4e 100644 --- a/src/core/themes/dark.ts +++ b/src/core/themes/dark.ts @@ -29,7 +29,7 @@ export const darkTheme: Theme = { })!, divider: lightTheme.palettes.gray[500], touchableHighlight: 'rgba(255, 255, 255, .08)', - agendaLecture: lightTheme.palettes.navy[100], + lectureCardSecondary: lightTheme.palettes.gray[300], tabBarInactive: lightTheme.palettes.gray[400], }, }; diff --git a/src/core/themes/light.ts b/src/core/themes/light.ts index 27a2f5f4..9836421d 100644 --- a/src/core/themes/light.ts +++ b/src/core/themes/light.ts @@ -158,10 +158,10 @@ export const lightTheme: Theme = { tabBar: navy[200], translucentSurface: 'rgba(0, 0, 0, .1)', tabBarInactive: gray[500], - agendaBooking: green[600], - agendaDeadline: red[700], - agendaExam: orange[600], - agendaLecture: navy[500], + bookingCardBorder: green[600], + deadlineCardBorder: red[700], + examCardBorder: orange[600], + lectureCardSecondary: gray[600], }, palettes: { navy, diff --git a/src/features/agenda/components/AgendaTabs.tsx b/src/features/agenda/components/AgendaTabs.tsx deleted file mode 100644 index 99d80456..00000000 --- a/src/features/agenda/components/AgendaTabs.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import { Platform, StyleSheet } from 'react-native'; - -import { Tab } from '@lib/ui/components/Tab'; -import { Tabs } from '@lib/ui/components/Tabs'; -import { useStylesheet } from '@lib/ui/hooks/useStylesheet'; -import { Theme } from '@lib/ui/types/Theme'; - -import { AgendaFiltersState } from '../types/AgendaFiltersState'; -import { AgendaItemType } from '../types/AgendaItem'; - -const activeTransparancyLight = '11'; -const activeTransparancyDark = '33'; - -interface Props { - state: AgendaFiltersState; - toggleState: (type: AgendaItemType) => void; -} - -export const AgendaTabs = ({ state, toggleState }: Props) => { - const { t } = useTranslation(); - - const styles = useStylesheet(createStyles); - - return ( - - toggleState('lecture')} - textStyle={state.lecture ? styles.tabText : styles.tabTextDisabled} - style={[ - styles.tab, - state.lecture ? styles.tabLecture : styles.tabDisabled, - ]} - > - {t('courseLecturesTab.title')} - - toggleState('exam')} - textStyle={state.exam ? styles.tabText : styles.tabTextDisabled} - style={[styles.tab, state.exam ? styles.tabExam : styles.tabDisabled]} - > - {t('examsScreen.title')} - - toggleState('booking')} - textStyle={state.booking ? styles.tabText : styles.tabTextDisabled} - style={[ - styles.tab, - state.booking ? styles.tabBooking : styles.tabDisabled, - ]} - > - {t('common.booking_plural')} - - toggleState('deadline')} - textStyle={state.deadline ? styles.tabText : styles.tabTextDisabled} - style={[ - styles.tab, - state.deadline ? styles.tabDeadline : styles.tabDisabled, - ]} - > - {t('common.deadline_plural')} - - - ); -}; - -const createStyles = ({ colors, palettes, dark }: Theme) => - StyleSheet.create({ - tabs: { - backgroundColor: colors.headersBackground, - borderBottomWidth: Platform.select({ - ios: StyleSheet.hairlineWidth, - }), - borderBottomColor: colors.divider, - elevation: 3, - zIndex: 1, - }, - tab: { - borderWidth: 1, - }, - tabText: { - color: colors.heading, - }, - tabTextDisabled: { - color: palettes.text[dark ? 400 : 500], - }, - // Theme-independent hardcoded color - // eslint-disable-next-line react-native/no-color-literals - tabDisabled: { - backgroundColor: 'transparent', - borderColor: palettes.text[dark ? 400 : 500], - }, - tabBooking: { - backgroundColor: - colors.agendaBooking + - (dark ? activeTransparancyDark : activeTransparancyLight), - borderColor: colors.agendaBooking, - }, - tabDeadline: { - backgroundColor: - colors.agendaDeadline + - (dark ? activeTransparancyDark : activeTransparancyLight), - borderColor: colors.agendaDeadline, - }, - tabExam: { - backgroundColor: - colors.agendaExam + - (dark ? activeTransparancyDark : activeTransparancyLight), - borderColor: colors.agendaExam, - }, - tabLecture: { - backgroundColor: - colors.agendaLecture + - (dark ? activeTransparancyDark : activeTransparancyLight), - borderColor: colors.agendaLecture, - }, - }); diff --git a/src/features/agenda/components/AgendaTypeFilter.tsx b/src/features/agenda/components/AgendaTypeFilter.tsx index 2fcbe091..78e6a120 100644 --- a/src/features/agenda/components/AgendaTypeFilter.tsx +++ b/src/features/agenda/components/AgendaTypeFilter.tsx @@ -41,18 +41,17 @@ export const AgendaTypeFilter = () => { const { colors } = useTheme(); - const colorsMap: Record = useMemo(() => { + const colorsMap: Record = useMemo(() => { return { - booking: colors.agendaBooking, - deadline: colors.agendaDeadline, - exam: colors.agendaExam, - lecture: colors.agendaLecture, + booking: colors.bookingCardBorder, + deadline: colors.deadlineCardBorder, + exam: colors.examCardBorder, + lecture: null, }; }, [ - colors.agendaBooking, - colors.agendaDeadline, - colors.agendaExam, - colors.agendaLecture, + colors.bookingCardBorder, + colors.deadlineCardBorder, + colors.examCardBorder, ]); const styles = useStylesheet(createStyles); @@ -69,7 +68,7 @@ export const AgendaTypeFilter = () => { } else { return selectedTypes.map(type => ( - + {getLocalizedType(type)} )); @@ -85,7 +84,7 @@ export const AgendaTypeFilter = () => { id: eventType, title, state: (filters[typedEventType] ? 'on' : 'off') as MenuAction['state'], - imageColor: colorsMap[typedEventType], + imageColor: colorsMap[typedEventType] ?? undefined, image: Platform.select({ ios: 'circle', android: 'circle', @@ -127,15 +126,12 @@ const createStyles = ({ colors, spacing }: Theme) => alignItems: 'center', }, tabBooking: { - borderColor: colors.agendaBooking, + borderColor: colors.bookingCardBorder, }, tabDeadline: { - borderColor: colors.agendaDeadline, + borderColor: colors.deadlineCardBorder, }, tabExam: { - borderColor: colors.agendaExam, - }, - tabLecture: { - borderColor: colors.agendaLecture, + borderColor: colors.examCardBorder, }, }); diff --git a/src/features/agenda/components/BookingCard.tsx b/src/features/agenda/components/BookingCard.tsx index 7178ec5e..d1db810d 100644 --- a/src/features/agenda/components/BookingCard.tsx +++ b/src/features/agenda/components/BookingCard.tsx @@ -21,7 +21,7 @@ export const BookingCard = ({ item, compact = false }: Props) => { diff --git a/src/features/agenda/components/DeadlineCard.tsx b/src/features/agenda/components/DeadlineCard.tsx index b17998b2..42100e5b 100644 --- a/src/features/agenda/components/DeadlineCard.tsx +++ b/src/features/agenda/components/DeadlineCard.tsx @@ -21,7 +21,7 @@ export const DeadlineCard = ({ item, compact = false }: Props) => { navigate({ diff --git a/src/features/agenda/components/ExamCard.tsx b/src/features/agenda/components/ExamCard.tsx index 1da34cdc..e11977e4 100644 --- a/src/features/agenda/components/ExamCard.tsx +++ b/src/features/agenda/components/ExamCard.tsx @@ -33,7 +33,7 @@ export const ExamCard = ({ item, compact = false }: Props) => { { const { navigate } = useNavigation>(); const { t } = useTranslation(); const styles = useStylesheet(createStyles); - const { colors, fontSizes } = useTheme(); + const { colors, fontSizes, dark } = useTheme(); + + const location = useMemo(() => { + if (!item.place?.name) return '-'; + + if (compact) return item.place.name; + + return t('agendaScreen.room', { roomName: item.place.name }); + }, [compact, item.place?.name, t]); return ( @@ -48,6 +52,10 @@ export const LectureCard = ({ item, compact = false }: Props) => { }, }) } + style={[ + styles.card, + { backgroundColor: item.color + (dark ? '80' : '30') }, + ]} > {item.virtualClassrooms?.map(vc => ( @@ -71,12 +79,18 @@ export const LectureCard = ({ item, compact = false }: Props) => { ); }; -const createStyles = ({ spacing }: Theme) => +const createStyles = ({ colors, spacing }: Theme) => StyleSheet.create({ + card: { + borderWidth: 0, + elevation: 0, + }, description: { + color: colors.lectureCardSecondary, marginTop: spacing[1.5], }, vcTitle: { + color: colors.lectureCardSecondary, marginLeft: spacing[1.5], }, vcRow: { From 9106186a086fec7acbb064a0d158d9df7a9813af Mon Sep 17 00:00:00 2001 From: Luca Pezzolla Date: Mon, 15 Apr 2024 18:57:55 +0200 Subject: [PATCH 2/2] chore(agenda): move place marker after place name in compact agenda --- lib/ui/components/AgendaCard.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/ui/components/AgendaCard.tsx b/lib/ui/components/AgendaCard.tsx index 0226f831..f8107fda 100644 --- a/lib/ui/components/AgendaCard.tsx +++ b/lib/ui/components/AgendaCard.tsx @@ -174,7 +174,7 @@ export const AgendaCard = ({ {/* Extra children are only shown if the card is not compact */} {!isCompact && children} - {location && ( + {!isCompact && location && ( )} + {isCompact && location && ( + + + {location} + + + + )}