Compare commits

..

1 Commits

Author SHA1 Message Date
Jorrin
52d6490951 Add direct bookmarking from movie thumbnails 2024-04-22 19:50:56 +02:00
8 changed files with 63 additions and 14 deletions

View File

@ -278,8 +278,7 @@
"loadingError": "Error loading season", "loadingError": "Error loading season",
"loadingList": "Loading...", "loadingList": "Loading...",
"loadingTitle": "Loading...", "loadingTitle": "Loading...",
"unairedEpisodes": "One or more episodes in this season have been disabled because they haven't been aired yet.", "unairedEpisodes": "One or more episodes in this season have been disabled because they haven't been aired yet."
"seasons": "Seasons"
}, },
"playback": { "playback": {
"speedLabel": "Playback speed", "speedLabel": "Playback speed",

View File

@ -25,7 +25,7 @@ export function EditButton(props: EditButtonProps) {
> >
<span ref={parent}> <span ref={parent}>
{props.editing ? ( {props.editing ? (
<span className="mx-2 sm:mx-4 whitespace-nowrap"> <span className="mx-4 whitespace-nowrap">
{t("home.mediaList.stopEditing")} {t("home.mediaList.stopEditing")}
</span> </span>
) : ( ) : (

View File

@ -2,7 +2,7 @@ import { Icon, Icons } from "@/components/Icon";
export interface IconPatchProps { export interface IconPatchProps {
active?: boolean; active?: boolean;
onClick?: () => void; onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
clickable?: boolean; clickable?: boolean;
className?: string; className?: string;
icon: Icons; icon: Icons;

View File

@ -10,6 +10,7 @@ import { MediaItem } from "@/utils/mediaTypes";
import { IconPatch } from "../buttons/IconPatch"; import { IconPatch } from "../buttons/IconPatch";
import { Icons } from "../Icon"; import { Icons } from "../Icon";
import { MediaCardBookmarkButton } from "../player/Player";
export interface MediaCardProps { export interface MediaCardProps {
media: MediaItem; media: MediaItem;
@ -22,6 +23,7 @@ export interface MediaCardProps {
}; };
percentage?: number; percentage?: number;
closable?: boolean; closable?: boolean;
shouldShowBookMark?: boolean;
onClose?: () => void; onClose?: () => void;
} }
@ -45,6 +47,7 @@ function MediaCardContent({
series, series,
percentage, percentage,
closable, closable,
shouldShowBookMark = true,
onClose, onClose,
}: MediaCardProps) { }: MediaCardProps) {
const { t } = useTranslation(); const { t } = useTranslation();
@ -153,6 +156,19 @@ function MediaCardContent({
icon={Icons.X} icon={Icons.X}
/> />
</div> </div>
{shouldShowBookMark && (
<div
className={classNames(
`absolute left-2 top-2 rounded-md transition-opacity opacity-0 group-hover:opacity-100 duration-300`,
{
"opacity-100": closable,
},
)}
>
<MediaCardBookmarkButton media={media} />
</div>
)}
</div> </div>
<h1 className="mb-1 line-clamp-3 max-h-[4.5rem] text-ellipsis break-words font-bold text-white"> <h1 className="mb-1 line-clamp-3 max-h-[4.5rem] text-ellipsis break-words font-bold text-white">
<span>{media.title}</span> <span>{media.title}</span>

View File

@ -22,6 +22,7 @@ function formatSeries(series?: ShowProgressResult | null) {
export interface WatchedMediaCardProps { export interface WatchedMediaCardProps {
media: MediaItem; media: MediaItem;
closable?: boolean; closable?: boolean;
shouldShowBookMark?: boolean;
onClose?: () => void; onClose?: () => void;
} }
@ -46,6 +47,7 @@ export function WatchedMediaCard(props: WatchedMediaCardProps) {
percentage={percentage} percentage={percentage}
onClose={props.onClose} onClose={props.onClose}
closable={props.closable} closable={props.closable}
shouldShowBookMark={props.shouldShowBookMark}
/> />
); );
} }

View File

@ -212,16 +212,9 @@ function EpisodesView({
return ( return (
<Menu.CardWithScrollable> <Menu.CardWithScrollable>
<Menu.BackLink <Menu.BackLink onClick={goBack}>
onClick={goBack} {loadingState?.value?.season.title ||
rightSide={ t("player.menus.episodes.loadingTitle")}
<span>
{loadingState?.value?.season.title ||
t("player.menus.episodes.loadingTitle")}
</span>
}
>
{t("player.menus.episodes.seasons")}
</Menu.BackLink> </Menu.BackLink>
{content} {content}
</Menu.CardWithScrollable> </Menu.CardWithScrollable>

View File

@ -1,8 +1,10 @@
import { useCallback } from "react"; import { useCallback } from "react";
import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { useBookmarkStore } from "@/stores/bookmarks"; import { useBookmarkStore } from "@/stores/bookmarks";
import { usePlayerStore } from "@/stores/player/store"; import { usePlayerStore } from "@/stores/player/store";
import { MediaItem } from "@/utils/mediaTypes";
import { VideoPlayerButton } from "./Button"; import { VideoPlayerButton } from "./Button";
@ -28,3 +30,39 @@ export function BookmarkButton() {
/> />
); );
} }
export function MediaCardBookmarkButton(props: { media: MediaItem }) {
const addBookmark = useBookmarkStore((s) => s.addBookmark);
const removeBookmark = useBookmarkStore((s) => s.removeBookmark);
const bookmarks = useBookmarkStore((s) => s.bookmarks);
const isBookmarked = !!bookmarks[props.media.id];
const toggleBookmark = useCallback(
(event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
event.preventDefault();
if (!props.media.year) return;
if (isBookmarked) {
removeBookmark(props.media.id);
} else {
addBookmark({
tmdbId: props.media.id,
title: props.media.title,
releaseYear: props.media.year,
type: props.media.type,
poster: props.media.poster,
});
}
},
[isBookmarked, props.media, addBookmark, removeBookmark],
);
if (!props.media.year) return null;
return (
<IconPatch
clickable
onClick={toggleBookmark}
icon={isBookmarked ? Icons.BOOKMARK : Icons.BOOKMARK_OUTLINE}
/>
);
}

View File

@ -58,6 +58,7 @@ export function BookmarksPart() {
media={v} media={v}
closable={editing} closable={editing}
onClose={() => removeBookmark(v.id)} onClose={() => removeBookmark(v.id)}
shouldShowBookMark={false}
/> />
))} ))}
</MediaGrid> </MediaGrid>