Skip to content

Commit

Permalink
feat: study queue buttons on Items page
Browse files Browse the repository at this point in the history
Closes #12
  • Loading branch information
Lemmmy committed Nov 20, 2023
1 parent 91d649c commit a5278a8
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 22 deletions.
15 changes: 12 additions & 3 deletions src/components/study-queue/StudyQueueButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ interface Props extends ButtonProps {
useShortTitle?: boolean;
noDanger?: boolean;
noTooltip?: boolean;
titles?: [string, string];
longTitles?: [string, string];
shortTitle?: string;
}

const defaultTitles: [string, string] = ["Add to study queue", "Remove from study queue"];
const defaultLongTitles: [string, string] = ["Add to self-study queue", "Remove from self-study queue"];

export function StudyQueueButton({
subjectId,
subjectIds,
Expand All @@ -30,14 +36,17 @@ export function StudyQueueButton({
noDanger,
noTooltip,
className,
titles = defaultTitles,
longTitles = defaultLongTitles,
shortTitle = "Queue",
...props
}: Props): JSX.Element {
const inQueue = useIsInStudyQueue(subjectId ?? -1);
const [hover, unhover] = useStudyQueueHover();

// Various titles depending on the circumstance
const longTitle = inQueue ? "Remove from self-study queue" : "Add to self-study queue";
const title = inQueue ? "Remove from study queue" : "Add to study queue";
const title = titles[+inQueue];
const longTitle = longTitles[+inQueue];

const classes = classNames("study-queue-button", className);

Expand Down Expand Up @@ -74,7 +83,7 @@ export function StudyQueueButton({
// Any user-defined button props
{...props}
>
{!iconOnly && (useShortTitle ? "Queue" : title)}
{!iconOnly && (useShortTitle ? shortTitle : title)}
</Button>;

return noTooltip
Expand Down
76 changes: 68 additions & 8 deletions src/pages/items/ItemsResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// This file is part of KanjiSchool under AGPL-3.0.
// Full details: https:/Lemmmy/KanjiSchool/blob/master/LICENSE

import { Divider } from "antd";
import classNames from "classnames";

import { LookupResults } from "./lookup";
Expand All @@ -12,21 +11,37 @@ import { SubjectGrid } from "@comp/subjects/lists/grid";
import { SubjectRenderTooltipFn } from "@comp/subjects/lists/tooltip/SubjectTooltip";

import { pluralN } from "@utils";
import { StudyQueueButton } from "@comp/study-queue/StudyQueueButton.tsx";
import { useMemo } from "react";
import memoizee from "memoizee";

type Props = LookupResults & {
colorBy: ItemsColorBy;
hasVocabulary: boolean;
renderTooltipFn: SubjectRenderTooltipFn;
groupNumber: number;
isSubgroup?: boolean;
parentTitle?: string;
};

const queueButtonTitles: [string, string] = ["Add all to study queue", "Remove all from study queue"];

function _makeLongTitles(title: string, parentTitle?: string): [string, string] {
const innerTitle = parentTitle ? `${parentTitle} > ${title}` : title;
return [
`Add all items in ${innerTitle} to self-study queue`,
`Remove all items in ${innerTitle} from self-study queue`
];
}
const makeLongTitles = memoizee(_makeLongTitles);

export function ItemsResults({
colorBy,
hasVocabulary,
renderTooltipFn,
groupNumber,
isSubgroup,
parentTitle,
...r
}: Props): JSX.Element {
// If there are subgroups, the item count is the sum of all the subgroups'
Expand All @@ -36,6 +51,13 @@ export function ItemsResults({
? r.items.reduce((sum, subgroup) => sum + subgroup.items.length, 0)
: r.items.length;

const allSubItems = useMemo(() => r.subgroups
? r.items.flatMap(subgroup => subgroup.items.map(i => i[0].id))
: r.items.map(i => i[0].id),
[r.subgroups, r.items]);

const queueButtonLongTitles = makeLongTitles(r.title, parentTitle);

const classes = classNames(
"max-w-[1080px] mx-auto",
{
Expand All @@ -45,27 +67,47 @@ export function ItemsResults({

return <div className={classes}>
{/* Header */}
<Divider
orientation="left"
<div
className={classNames(
"before:!w-[32px] before:!translate-y-px after:!translate-y-px", // 50% y makes the divider 2px thick, yuck
"flex items-center h-[27px] gap-md my-md",
{
"mb-xs": r.subgroups,
["font-normal !text-sm !border-bs-white/8 !border-be-white/8 " +
"light:!border-bs-black/10 light:!border-be-black/10"]: isSubgroup
"font-normal !text-sm": isSubgroup
}
)}
>
{/* Start line */}
<Line short subgroup={isSubgroup} />

{/* Title */}
<span className="mr-[1em]">
<span className={isSubgroup ? "font-normal text-sm" : "font-semibold text-lg"}>
{r.title}
</span>

{/* Count */}
<span className="text-desc text-sm font-normal">
{pluralN(itemCount, "item")}
</span>
</Divider>

{/* End line */}
<Line subgroup={isSubgroup} />

{/* Add to study queue button */}
{allSubItems.length > 0 && <StudyQueueButton
type="link"
size="small"
className={classNames(
"text-desc hover:!text-white/75 light:hover:!text-black/75",
{
"opacity-75": isSubgroup,
}
)}
subjectIds={allSubItems}
titles={queueButtonTitles}
longTitles={queueButtonLongTitles}
useShortTitle={isSubgroup}
/>}
</div>

{/* Display a subgroup or the item listing depending */}
{r.subgroups
Expand All @@ -77,6 +119,7 @@ export function ItemsResults({
groupNumber={r2.group}
{...r2}
isSubgroup
parentTitle={r.title}
/>))
: <SubjectGrid
size="tiny"
Expand All @@ -89,3 +132,20 @@ export function ItemsResults({
/>}
</div>;
}

interface LineProps {
short?: boolean;
subgroup?: boolean;
}

const Line = ({ short, subgroup }: LineProps) => <span
className={classNames(
"border-0 border-b border-solid",
{
"w-[32px]": short,
"flex-1": !short,
"border-b-white/15 light:border-b-black/15": !subgroup,
"border-b-white/8 light:border-b-black/10": subgroup,
}
)}
/>;
18 changes: 10 additions & 8 deletions src/pages/items/lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// This file is part of KanjiSchool under AGPL-3.0.
// Full details: https:/Lemmmy/KanjiSchool/blob/master/LICENSE

import { ReactNode } from "react";

import { store } from "@store";
import { SubjectWithAssignment } from "@api";

Expand All @@ -21,14 +19,14 @@ export type LookupResults = ResultGroupSet | ResultSet;
export interface ResultGroupSet {
subgroups: true;
group: number;
title: ReactNode;
title: string;
items: ResultSet[];
}

export interface ResultSet {
subgroups: false;
group: number;
title: ReactNode;
title: string;
items: SubjectWithAssignment[];
itemIds: number[];
}
Expand All @@ -43,10 +41,14 @@ export function lookupItems(
type: ItemsBaseType,
{
frequencyGroupSize = 500,
sortBy = "slug", sortByOrder = "asc",
groupByPrimary, groupByPrimaryOrder = "asc",
groupBySecondary, groupBySecondaryOrder = "asc",
types, srsStages
sortBy = "slug",
sortByOrder = "asc",
groupByPrimary,
groupByPrimaryOrder = "asc",
groupBySecondary,
groupBySecondaryOrder = "asc",
types,
srsStages
}: FormValues
): LookupResults[] {
const { subjects } = store.getState().subjects;
Expand Down
4 changes: 1 addition & 3 deletions src/pages/items/types/groupFns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// This file is part of KanjiSchool under AGPL-3.0.
// Full details: https:/Lemmmy/KanjiSchool/blob/master/LICENSE

import { ReactNode } from "react";

import { SubjectWithAssignment } from "@api";

import {
Expand Down Expand Up @@ -32,7 +30,7 @@ export const GROUP_BY_FNS: Record<ItemsGroupBy, GroupByFn> = {
export type GroupToNodeFn = (
n: number,
freqGroupSize: number
) => ReactNode;
) => string;

export const GROUP_BY_TO_NODE_FNS: Record<ItemsGroupBy, GroupToNodeFn> = {
"level": n => `Level ${n}`,
Expand Down

0 comments on commit a5278a8

Please sign in to comment.