Skip to content

Commit fc5962f

Browse files
committed
feat: show pinned count
1 parent fb3c17d commit fc5962f

File tree

6 files changed

+37
-6
lines changed

6 files changed

+37
-6
lines changed

server/router/api/v1/memo_service_filter.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func (s *APIV1Service) buildMemoFindWithFilter(ctx context.Context, find *store.
5252
find.CreatedTsBefore = filterExpr.DisplayTimeBefore
5353
}
5454
}
55+
if filterExpr.Pinned {
56+
pinned := true
57+
find.Pinned = &pinned
58+
}
5559
if filterExpr.HasLink {
5660
find.PayloadFind.HasLink = true
5761
}
@@ -74,6 +78,7 @@ var MemoFilterCELAttributes = []cel.EnvOption{
7478
cel.Variable("tag_search", cel.ListType(cel.StringType)),
7579
cel.Variable("display_time_before", cel.IntType),
7680
cel.Variable("display_time_after", cel.IntType),
81+
cel.Variable("pinned", cel.BoolType),
7782
cel.Variable("has_link", cel.BoolType),
7883
cel.Variable("has_task_list", cel.BoolType),
7984
cel.Variable("has_code", cel.BoolType),
@@ -85,6 +90,7 @@ type MemoFilter struct {
8590
TagSearch []string
8691
DisplayTimeBefore *int64
8792
DisplayTimeAfter *int64
93+
Pinned bool
8894
HasLink bool
8995
HasTaskList bool
9096
HasCode bool
@@ -134,6 +140,9 @@ func findMemoField(callExpr *exprv1.Expr_Call, filter *MemoFilter) {
134140
} else if idExpr.Name == "display_time_after" {
135141
displayTimeAfter := callExpr.Args[1].GetConstExpr().GetInt64Value()
136142
filter.DisplayTimeAfter = &displayTimeAfter
143+
} else if idExpr.Name == "pinned" {
144+
value := callExpr.Args[1].GetConstExpr().GetBoolValue()
145+
filter.Pinned = value
137146
} else if idExpr.Name == "has_link" {
138147
value := callExpr.Args[1].GetConstExpr().GetBoolValue()
139148
filter.HasLink = value

web/src/components/MemoFilters.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isEqual } from "lodash-es";
2-
import { CalendarIcon, CheckCircleIcon, CodeIcon, EyeIcon, HashIcon, LinkIcon, SearchIcon, XIcon } from "lucide-react";
2+
import { CalendarIcon, CheckCircleIcon, CodeIcon, EyeIcon, HashIcon, LinkIcon, PinIcon, SearchIcon, XIcon } from "lucide-react";
33
import { useEffect } from "react";
44
import { useSearchParams } from "react-router-dom";
55
import { FilterFactor, getMemoFilterKey, MemoFilter, stringifyFilters, useMemoFilterStore } from "@/store/v1";
@@ -68,6 +68,7 @@ const FactorIcon = ({ factor, className }: { factor: FilterFactor; className?: s
6868
visibility: <EyeIcon className={className} />,
6969
contentSearch: <SearchIcon className={className} />,
7070
displayTime: <CalendarIcon className={className} />,
71+
pinned: <PinIcon className={className} />,
7172
"property.hasLink": <LinkIcon className={className} />,
7273
"property.hasTaskList": <CheckCircleIcon className={className} />,
7374
"property.hasCode": <CodeIcon className={className} />,

web/src/components/StatisticsView.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { Tooltip } from "@mui/joy";
22
import dayjs from "dayjs";
33
import { countBy } from "lodash-es";
4-
import { CheckCircleIcon, ChevronRightIcon, ChevronLeftIcon, Code2Icon, LinkIcon, ListTodoIcon } from "lucide-react";
4+
import { CheckCircleIcon, ChevronRightIcon, ChevronLeftIcon, Code2Icon, LinkIcon, ListTodoIcon, PinIcon } from "lucide-react";
55
import { observer } from "mobx-react-lite";
66
import { useState } from "react";
77
import DatePicker from "react-datepicker";
8+
import { matchPath, useLocation } from "react-router-dom";
89
import useAsyncEffect from "@/hooks/useAsyncEffect";
10+
import useCurrentUser from "@/hooks/useCurrentUser";
911
import i18n from "@/i18n";
12+
import { Routes } from "@/router";
1013
import { useMemoFilterStore } from "@/store/v1";
1114
import { userStore } from "@/store/v2";
1215
import { UserStats_MemoTypeStats } from "@/types/proto/api/v1/user_service";
@@ -17,7 +20,9 @@ import "react-datepicker/dist/react-datepicker.css";
1720

1821
const StatisticsView = observer(() => {
1922
const t = useTranslate();
23+
const location = useLocation();
2024
const memoFilterStore = useMemoFilterStore();
25+
const currentUser = useCurrentUser();
2126
const [memoTypeStats, setMemoTypeStats] = useState<UserStats_MemoTypeStats>(UserStats_MemoTypeStats.fromPartial({}));
2227
const [activityStats, setActivityStats] = useState<Record<string, number>>({});
2328
const [selectedDate] = useState(new Date());
@@ -92,7 +97,22 @@ const StatisticsView = observer(() => {
9297
onClick={onCalendarClick}
9398
/>
9499
</div>
95-
<div className="pt-1 w-full flex flex-row justify-start items-center gap-x-2 gap-y-1 flex-wrap">
100+
<div className="pt-1 w-full flex flex-row justify-start items-center gap-1 flex-wrap">
101+
{matchPath(Routes.ROOT, location.pathname) &&
102+
currentUser &&
103+
userStore.state.currentUserStats &&
104+
userStore.state.currentUserStats.pinnedMemos.length > 0 && (
105+
<div
106+
className={cn("w-auto border dark:border-zinc-800 pl-1.5 pr-2 py-0.5 rounded-md flex justify-between items-center")}
107+
onClick={() => memoFilterStore.addFilter({ factor: "pinned", value: "" })}
108+
>
109+
<div className="w-auto flex justify-start items-center mr-1">
110+
<PinIcon className="w-4 h-auto mr-1" />
111+
<span className="block text-sm">Pinned</span>
112+
</div>
113+
<span className="text-sm truncate">{userStore.state.currentUserStats.pinnedMemos.length}</span>
114+
</div>
115+
)}
96116
<div
97117
className={cn("w-auto border dark:border-zinc-800 pl-1.5 pr-2 py-0.5 rounded-md flex justify-between items-center")}
98118
onClick={() => memoFilterStore.addFilter({ factor: "property.hasLink", value: "" })}

web/src/pages/Home.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ const Home = observer(() => {
2323
contentSearch.push(`"${filter.value}"`);
2424
} else if (filter.factor === "tagSearch") {
2525
tagSearch.push(`"${filter.value}"`);
26+
} else if (filter.factor === "pinned") {
27+
conditions.push(`pinned == true`);
2628
} else if (filter.factor === "property.hasLink") {
2729
conditions.push(`has_link == true`);
2830
} else if (filter.factor === "property.hasTaskList") {

web/src/pages/UserProfile.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { observer } from "mobx-react-lite";
66
import { useEffect, useMemo, useState } from "react";
77
import { toast } from "react-hot-toast";
88
import { useParams } from "react-router-dom";
9-
import MemoFilters from "@/components/MemoFilters";
109
import MemoView from "@/components/MemoView";
1110
import PagedMemoList from "@/components/PagedMemoList";
1211
import UserAvatar from "@/components/UserAvatar";
@@ -78,7 +77,7 @@ const UserProfile = observer(() => {
7877

7978
return (
8079
<section className="w-full max-w-3xl mx-auto min-h-full flex flex-col justify-start items-center pb-8">
81-
<div className="w-full px-4 sm:px-6 flex flex-col justify-start items-center">
80+
<div className="w-full flex flex-col justify-start items-center max-w-2xl">
8281
{!loadingState.isLoading &&
8382
(user ? (
8483
<>
@@ -99,7 +98,6 @@ const UserProfile = observer(() => {
9998
</p>
10099
</div>
101100
</div>
102-
<MemoFilters />
103101
<PagedMemoList
104102
renderer={(memo: Memo) => (
105103
<MemoView key={`${memo.name}-${memo.displayTime}`} memo={memo} showVisibility showPinned compact />

web/src/store/v1/memoFilter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type FilterFactor =
77
| "visibility"
88
| "contentSearch"
99
| "displayTime"
10+
| "pinned"
1011
| "property.hasLink"
1112
| "property.hasTaskList"
1213
| "property.hasCode";

0 commit comments

Comments
 (0)