Skip to content

Commit

Permalink
Display inline progress for media progress (#1093)
Browse files Browse the repository at this point in the history
* fix(website): invalidate old keys

* chore(website): hide links

* chore(website): hide more links

* fix(frontend): refresh metadata details on adding to collection

* fix(website): add more padding etc

* fix(website): remove carousel b tns

* refactor(frontend): move location of item

* ci(ts): downgrade tabler icons version

Ref: tabler/tabler-icons#1233

* refactor(frontend): use correct imports

* feat(frontend): display inline progress

* feat(frontend): change orientation of inline progress bar

* chore(models/user): remove repeated stuff

* chore(backend): add new column for deduplicating upcoming section

* chore(gql): generate new types

* fix(frontend): better logic to decide which elements should show

* feat(frontend): deduplicate media

* fix(services/misc): respect new preferences

* fix(frontend): add docs for deduplicate option

* build(ts): upgrade deps

* refactor(frontend): change name of param
  • Loading branch information
IgnisDa authored Nov 2, 2024
1 parent 5520313 commit a112599
Show file tree
Hide file tree
Showing 20 changed files with 343 additions and 496 deletions.
164 changes: 162 additions & 2 deletions apps/frontend/app/components/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ import {
Badge,
Box,
Button,
Center,
Checkbox,
Collapse,
Divider,
Flex,
Group,
Image,
type MantineStyleProp,
Modal,
MultiSelect,
Paper,
SimpleGrid,
Skeleton,
Stack,
Text,
TextInput,
Expand Down Expand Up @@ -47,7 +50,13 @@ import {
type ReviewItem,
UserReviewScale,
} from "@ryot/generated/graphql/backend/graphql";
import { changeCase, getInitials, isNumber, snakeCase } from "@ryot/ts-utils";
import {
changeCase,
getInitials,
isNumber,
isString,
snakeCase,
} from "@ryot/ts-utils";
import {
IconArrowBigUp,
IconCheck,
Expand All @@ -64,7 +73,7 @@ import {
} from "@tabler/icons-react";
import { useMutation, useQuery } from "@tanstack/react-query";
import Cookies from "js-cookie";
import type { ReactNode } from "react";
import type { ReactNode, Ref } from "react";
import { useState } from "react";
import { $path } from "remix-routes";
import type { DeepPartial } from "ts-essentials";
Expand Down Expand Up @@ -312,6 +321,157 @@ export const ProRequiredAlert = (props: { tooltipLabel?: string }) => {
) : null;
};

const blackBgStyles = {
backgroundColor: "rgba(0, 0, 0, 0.75)",
borderRadius: 3,
padding: 2,
} satisfies MantineStyleProp;

export const BaseMediaDisplayItem = (props: {
name?: string;
altName?: string;
progress?: string;
isLoading: boolean;
nameRight?: ReactNode;
imageUrl?: string | null;
innerRef?: Ref<HTMLDivElement>;
labels?: { right?: ReactNode; left?: ReactNode };
onImageClickBehavior: string | (() => Promise<void>);
imageOverlay?: {
topRight?: ReactNode;
topLeft?: ReactNode;
bottomRight?: ReactNode;
bottomLeft?: ReactNode;
};
}) => {
const userPreferences = useUserPreferences();
const gridPacking = userPreferences.general.gridPacking;
const SurroundingElement = (iProps: { children: ReactNode }) =>
isString(props.onImageClickBehavior) ? (
<Anchor component={Link} to={props.onImageClickBehavior}>
{iProps.children}
</Anchor>
) : (
<Box onClick={props.onImageClickBehavior}>{iProps.children}</Box>
);
const defaultOverlayProps = {
style: { zIndex: 10, ...blackBgStyles },
pos: "absolute",
} as const;

return (
<Flex justify="space-between" direction="column" ref={props.innerRef}>
<Box pos="relative" w="100%">
<SurroundingElement>
<Tooltip label={props.name} position="top">
<Paper style={{ overflow: "hidden" }} pos="relative" radius="md">
<Image
src={props.imageUrl}
style={{
cursor: "pointer",
...match(gridPacking)
.with(GridPacking.Normal, () => ({ height: 260 }))
.with(GridPacking.Dense, () => ({ height: 180 }))
.exhaustive(),
}}
alt={`Image for ${props.name}`}
className={classes.mediaImage}
styles={{
root: {
transitionProperty: "transform",
transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
transitionDuration: "150ms",
},
}}
fallbackSrc={useFallbackImageUrl(
props.isLoading
? "Loading..."
: props.name
? getInitials(props.name)
: undefined,
)}
/>
{props.progress ? (
<Paper
h={5}
bg="red"
left={0}
bottom={0}
pos="absolute"
w={`${props.progress}%`}
/>
) : null}
</Paper>
</Tooltip>
</SurroundingElement>
{props.imageOverlay?.topLeft ? (
<Center top={5} left={5} {...defaultOverlayProps}>
{props.imageOverlay.topLeft}
</Center>
) : null}
{props.imageOverlay?.topRight ? (
<Center top={5} right={5} {...defaultOverlayProps}>
{props.imageOverlay.topRight}
</Center>
) : null}
{props.imageOverlay?.bottomLeft ? (
<Center
left={5}
bottom={props.progress ? 8 : 5}
{...defaultOverlayProps}
>
{props.imageOverlay.bottomLeft}
</Center>
) : null}
{props.imageOverlay?.bottomRight ? (
<Center
right={5}
bottom={props.progress ? 8 : 5}
{...defaultOverlayProps}
>
{props.imageOverlay.bottomRight}
</Center>
) : null}
</Box>
{props.isLoading ? (
<>
<Skeleton height={22} mt={10} />
<Skeleton height={22} mt={8} />
</>
) : (
<Flex
w="100%"
direction="column"
mt={2}
px={match(gridPacking)
.with(GridPacking.Normal, () => ({ base: 6, md: 3 }))
.with(GridPacking.Dense, () => ({ md: 2 }))
.exhaustive()}
>
<Flex w="100%" direction="row" justify="space-between">
<Text
size="sm"
c="dimmed"
visibleFrom={gridPacking === GridPacking.Dense ? "md" : undefined}
>
{props.labels?.left}
</Text>
<Text c="dimmed" size="sm">
{props.labels?.right}
</Text>
</Flex>
<Flex mb="xs" align="center" justify="space-between">
<Text w="100%" truncate fw="bold">
{props.altName ?? props.name}
</Text>
{props.nameRight}
</Flex>
</Flex>
)}
</Flex>
);
};

export const FiltersModal = (props: {
opened: boolean;
cookieName: string;
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/app/components/fitness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import type { ComponentType, ReactNode } from "react";
import { $path } from "remix-routes";
import { match } from "ts-pattern";
import { withFragment } from "ufo";
import { BaseMediaDisplayItem } from "~/components/common";
import { FitnessEntity, dayjsLib, getSetColor } from "~/lib/generals";
import { useGetRandomMantineColor, useUserUnitSystem } from "~/lib/hooks";
import {
Expand All @@ -52,7 +53,6 @@ import {
getWorkoutDetailsQuery,
getWorkoutTemplateDetailsQuery,
} from "~/lib/state/fitness";
import { BaseMediaDisplayItem } from "./media";

export const getSetStatisticsTextToDisplay = (
lot: ExerciseLot,
Expand Down
Loading

0 comments on commit a112599

Please sign in to comment.