Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 541d0a3

Browse files
feat(pages): add popup menus to page items
1 parent fa8757b commit 541d0a3

File tree

16 files changed

+279
-184
lines changed

16 files changed

+279
-184
lines changed

‎apps/app-server/src/trpc/api/users/pages/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { getCurrentPathProcedure } from './get-current-path';
77
import { getGroupIdsProcedure } from './get-group-ids';
88
import { getStartingPageIdProcedure } from './get-starting-page-id';
99
import { notificationsRouter } from './notifications';
10-
import { removeFavoritePageProcedure } from './remove-favorite-page';
11-
import { removeRecentPageProcedure } from './remove-recent-page';
10+
import { removeFavoritePagesProcedure } from './remove-favorite-pages';
11+
import { removeRecentPagesProcedure } from './remove-recent-pages';
1212
import { setEncryptedDefaultArrowProcedure } from './set-encrypted-default-arrow';
1313
import { setEncryptedDefaultNoteProcedure } from './set-encrypted-default-note';
1414

@@ -18,11 +18,11 @@ export const pagesRouter = trpc.router({
1818
getStartingPageId: getStartingPageIdProcedure(),
1919
getCurrentPath: getCurrentPathProcedure(),
2020

21-
removeRecentPage: removeRecentPageProcedure(),
21+
removeRecentPages: removeRecentPagesProcedure(),
2222
clearRecentPages: clearRecentPagesProcedure(),
2323

2424
addFavoritePages: addFavoritePagesProcedure(),
25-
removeFavoritePage: removeFavoritePageProcedure(),
25+
removeFavoritePages: removeFavoritePagesProcedure(),
2626
clearFavoritePages: clearFavoritePagesProcedure(),
2727

2828
setEncryptedDefaultNote: setEncryptedDefaultNoteProcedure(),

‎apps/app-server/src/trpc/api/users/pages/remove-favorite-page.ts renamed to ‎apps/app-server/src/trpc/api/users/pages/remove-favorite-pages.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { z } from 'zod';
88

99
const baseProcedure = authProcedure.input(
1010
z.object({
11-
pageId: z.string().refine(isNanoID),
11+
pageIds: z.string().refine(isNanoID).array(),
1212
}),
1313
);
1414

15-
export const removeFavoritePageProcedure = once(() =>
15+
export const removeFavoritePagesProcedure = once(() =>
1616
baseProcedure.mutation(removeFavoritePage),
1717
);
1818

@@ -35,7 +35,7 @@ export async function removeFavoritePage({
3535

3636
const originalLength = favoritePageIds.length;
3737

38-
if (pull(favoritePageIds, input.pageId).length === originalLength) {
38+
if (pull(favoritePageIds, ...input.pageIds).length === originalLength) {
3939
throw new TRPCError({
4040
message: 'Favorite page not found.',
4141
code: 'NOT_FOUND',

‎apps/app-server/src/trpc/api/users/pages/remove-recent-page.ts renamed to ‎apps/app-server/src/trpc/api/users/pages/remove-recent-pages.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ import { z } from 'zod';
88

99
const baseProcedure = authProcedure.input(
1010
z.object({
11-
pageId: z.string().refine(isNanoID),
11+
pageIds: z.string().refine(isNanoID).array(),
1212
}),
1313
);
1414

15-
export const removeRecentPageProcedure = once(() =>
16-
baseProcedure.mutation(removeRecentPage),
15+
export const removeRecentPagesProcedure = once(() =>
16+
baseProcedure.mutation(removeRecentPages),
1717
);
1818

19-
export async function removeRecentPage({
19+
export async function removeRecentPages({
2020
ctx,
2121
input,
2222
}: InferProcedureOpts<typeof baseProcedure>) {
@@ -35,7 +35,7 @@ export async function removeRecentPage({
3535

3636
const originalLength = recentPageIds.length;
3737

38-
if (pull(recentPageIds, input.pageId).length === originalLength) {
38+
if (pull(recentPageIds, ...input.pageIds).length === originalLength) {
3939
throw new TRPCError({
4040
message: 'Recent page not found.',
4141
code: 'NOT_FOUND',

‎apps/client/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ yarn-error.log*
3131
*.ntvs*
3232
*.njsproj
3333
*.sln
34+
35+
/auto-imports.d.ts
36+
/components.d.ts
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { pluralS } from '@stdlib/misc';
2+
import { handleError } from 'src/code/utils/misc';
3+
4+
export async function addFavoritePages(pageIds: string[]) {
5+
try {
6+
await trpcClient.users.pages.addFavoritePages.mutate({
7+
pageIds: pageIds,
8+
});
9+
10+
$quasar().notify({
11+
message: `Page${pluralS(pageIds.length)} added to favorites.`,
12+
color: 'positive',
13+
});
14+
} catch (error) {
15+
handleError(error);
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { pluralS } from '@stdlib/misc';
2+
import { handleError } from 'src/code/utils/misc';
3+
4+
export async function removeFavoritePages(pageIds: string[]) {
5+
try {
6+
await trpcClient.users.pages.removeFavoritePages.mutate({
7+
pageIds: pageIds,
8+
});
9+
10+
$quasar().notify({
11+
message: `Page${pluralS(pageIds.length)} removed from favorites.`,
12+
color: 'negative',
13+
});
14+
} catch (error) {
15+
handleError(error);
16+
}
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { pull } from 'lodash';
2+
import { handleError } from 'src/code/utils/misc';
3+
4+
export async function removeRecentPages(pageIds: string[]) {
5+
try {
6+
await trpcClient.users.pages.removeRecentPages.mutate({
7+
pageIds: pageIds,
8+
});
9+
10+
internals.pages.recentPageIdsKeepOverride = true;
11+
internals.pages.react.recentPageIdsOverride =
12+
internals.pages.react.recentPageIds
13+
.filter((pageId) =>
14+
internals.realtime.globalCtx.hget('page', pageId, 'exists'),
15+
)
16+
.slice();
17+
pull(internals.pages.react.recentPageIdsOverride, ...pageIds);
18+
} catch (error) {
19+
handleError(error);
20+
}
21+
}

‎apps/client/src/components/PageItem.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
:page-id="pageId"
2121
:prefer="prefer"
2222
/>
23+
24+
<slot></slot>
2325
</q-item>
2426
</a>
2527
</template>
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<template>
2+
<DeepBtn
3+
icon="mdi-dots-vertical"
4+
round
5+
flat
6+
style="min-width: 0; min-height: 0; width: 32px; height: 32px"
7+
@click.stop
8+
>
9+
<q-menu
10+
v-bind="menuProps"
11+
auto-close
12+
@before-show="beforeShow"
13+
>
14+
<q-list>
15+
<q-item
16+
v-if="internals.pages.react.recentPageIds.includes(pageId)"
17+
clickable
18+
v-ripple
19+
@click="removeRecentPages([pageId])"
20+
>
21+
<q-item-section avatar>
22+
<q-icon name="mdi-trash-can" />
23+
</q-item-section>
24+
25+
<q-item-section>
26+
<q-item-label>Remove from recent pages</q-item-label>
27+
</q-item-section>
28+
</q-item>
29+
30+
<q-item
31+
v-if="pageFavorited"
32+
clickable
33+
v-ripple
34+
@click="removeFavoritePages([pageId])"
35+
>
36+
<q-item-section avatar>
37+
<q-icon name="mdi-star" />
38+
</q-item-section>
39+
40+
<q-item-section>
41+
<q-item-label>Remove from favorite pages</q-item-label>
42+
</q-item-section>
43+
</q-item>
44+
<q-item
45+
v-else
46+
clickable
47+
v-ripple
48+
@click="addFavoritePages([pageId])"
49+
>
50+
<q-item-section avatar>
51+
<q-icon name="mdi-star" />
52+
</q-item-section>
53+
54+
<q-item-section>
55+
<q-item-label>Add to favorite pages</q-item-label>
56+
</q-item-section>
57+
</q-item>
58+
59+
<q-item
60+
v-if="pageSelected"
61+
clickable
62+
v-ripple
63+
@click="deselectPage"
64+
>
65+
<q-item-section avatar>
66+
<q-icon name="mdi-selection-multiple" />
67+
</q-item-section>
68+
69+
<q-item-section>
70+
<q-item-label>Remove from selected pages</q-item-label>
71+
</q-item-section>
72+
</q-item>
73+
<q-item
74+
v-else
75+
clickable
76+
v-ripple
77+
@click="selectPage"
78+
>
79+
<q-item-section avatar>
80+
<q-icon name="mdi-selection-multiple" />
81+
</q-item-section>
82+
83+
<q-item-section>
84+
<q-item-label>Add to selected pages</q-item-label>
85+
</q-item-section>
86+
</q-item>
87+
88+
<slot></slot>
89+
</q-list>
90+
</q-menu>
91+
</DeepBtn>
92+
</template>
93+
94+
<script setup lang="ts">
95+
import type { QMenuProps } from 'quasar';
96+
import { addFavoritePages } from 'src/code/api-interface/users/add-favorite-pages';
97+
import { removeFavoritePages } from 'src/code/api-interface/users/remove-favorite-pages';
98+
import { removeRecentPages } from 'src/code/api-interface/users/remove-recent-pages';
99+
import { pageSelectionStore } from 'src/stores/page-selection';
100+
101+
import type { DeepBtnProps } from './DeepBtn.vue';
102+
103+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
104+
interface Props extends DeepBtnProps {
105+
pageId: string;
106+
107+
menuProps?: QMenuProps;
108+
}
109+
110+
const props = defineProps<Props>();
111+
112+
const pageFavorited = ref(false);
113+
const pageSelected = ref(false);
114+
115+
function beforeShow() {
116+
pageFavorited.value = internals.pages.react.favoritePageIds.includes(
117+
props.pageId,
118+
);
119+
pageSelected.value = pageSelectionStore().selectedPages.has(props.pageId);
120+
}
121+
122+
function selectPage() {
123+
pageSelectionStore().selectedPages.add(props.pageId);
124+
125+
$quasar().notify({
126+
message: 'Page added to selection.',
127+
color: 'positive',
128+
timeout: 1000,
129+
});
130+
}
131+
132+
function deselectPage() {
133+
pageSelectionStore().selectedPages.delete(props.pageId);
134+
135+
$quasar().notify({
136+
message: 'Page removed from selection.',
137+
color: 'negative',
138+
timeout: 1000,
139+
});
140+
}
141+
</script>

‎apps/client/src/layouts/PagesLayout/LeftSidebar/CurrentPath.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@
5050
:page-id="pageId"
5151
:active="pageId === internals.pages.react.pageId"
5252
prefer="relative"
53-
class="current-path"
54-
/>
53+
style="padding-right: 8px"
54+
>
55+
<q-item-section side>
56+
<PagePopupOptions :page-id="pageId" />
57+
</q-item-section>
58+
</PageItem>
5559
</q-list>
5660

5761
<div
@@ -79,6 +83,7 @@
7983

8084
<script setup lang="ts">
8185
import { listenPointerEvents, map, negateProp } from '@stdlib/misc';
86+
import PagePopupOptions from 'src/components/PagePopupOptions.vue';
8287
import type { LeftSidebarSectionName } from 'src/stores/ui';
8388
import {
8489
leftSidebarSectionIndexes,

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /