From cc52c60aa069430e8c37945a1068fdc4f515c3b7 Mon Sep 17 00:00:00 2001 From: penge Date: Tue, 24 May 2022 22:43:58 +0200 Subject: [PATCH 1/3] Fix notes scrolling in sidebar --- static/notes.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/notes.css b/static/notes.css index a9ae16ac..d298e8bf 100644 --- a/static/notes.css +++ b/static/notes.css @@ -146,6 +146,7 @@ body:not(.with-sidebar) { left: 0 !important; } flex-grow: 1; background: var(--sidebar-notes-background-color); color: var(--sidebar-notes-text-color); + overflow-y: auto; } #sidebar-notes-separator { @@ -154,7 +155,6 @@ body:not(.with-sidebar) { left: 0 !important; } .sidebar-notes { padding: .5em; - overflow-y: auto; } .sidebar-notes .note { From aa47919febaf6d200b6ecf4157aac462e79f5d14 Mon Sep 17 00:00:00 2001 From: penge Date: Wed, 25 May 2022 00:20:30 +0200 Subject: [PATCH 2/3] Sort Command palette notes same as in Sidebar --- src/notes.tsx | 8 +- src/notes/adapters/__tests__/index.test.ts | 119 ++++++++++++++---- src/notes/components/CommandPalette.tsx | 24 ++-- .../__tests__/CommandPalette.test.tsx | 15 ++- src/notes/sort/index.ts | 26 +++- 5 files changed, 147 insertions(+), 45 deletions(-) diff --git a/src/notes.tsx b/src/notes.tsx index bc5dd6e4..f9d02652 100644 --- a/src/notes.tsx +++ b/src/notes.tsx @@ -505,6 +505,10 @@ const Notes = (): h.JSX.Element => { // Command Palette const [setOnToggleCommandPaletteHandler] = useKeyboardShortcut(KeyboardShortcut.OnToggleCommandPalette); useEffect(() => { + if (!notesOrder) { + return; + } + // Detach when there are no notes if (!Object.keys(notesProps.notes).length) { setOnToggleCommandPaletteHandler(undefined); @@ -518,7 +522,7 @@ const Notes = (): h.JSX.Element => { // Props for Command Palette const props: CommandPaletteProps = { - notes: notesProps.notes, + notes: notesToSidebarNotes(notesProps.notes, notesOrder, order), commands, onActivateNote: (noteName: string) => { setCommandPaletteProps(null); @@ -551,7 +555,7 @@ const Notes = (): h.JSX.Element => { // Update props for already visible Command Palette setCommandPaletteProps((prev) => !prev ? prev : props); - }, [os, notesProps, handleOnActivateNote, commandPaletteCommands]); + }, [os, notesProps, notesOrder, order, handleOnActivateNote, commandPaletteCommands]); // Automatically show modal to create a new note if there are 0 notes useEffect(() => { diff --git a/src/notes/adapters/__tests__/index.test.ts b/src/notes/adapters/__tests__/index.test.ts index 3a20ad20..4aa835bc 100644 --- a/src/notes/adapters/__tests__/index.test.ts +++ b/src/notes/adapters/__tests__/index.test.ts @@ -1,29 +1,98 @@ import { NotesObject, NotesOrder } from "shared/storage/schema"; import { notesToSidebarNotes } from "../"; -test("notesToSidebarNotes() returns notes suitable for the Sidebar", () => { - const notes: NotesObject = { - Todo: { - content: "my todo", - createdTime: "CT-TODO", - modifiedTime: "MT-TODO", - }, - Article: { - content: "my article", - createdTime: "CT-ARTICLE", - modifiedTime: "MT-ARTICLE", - }, - Shopping: { - content: "my shopping", - createdTime: "CT-SHOPPING", - modifiedTime: "MT-SHOPPING", - }, - }; - - const sidebarNotes = notesToSidebarNotes(notes, NotesOrder.Alphabetical); - expect(sidebarNotes).toEqual([ - { name: "Article", ...notes.Article }, - { name: "Shopping", ...notes.Shopping }, - { name: "Todo", ...notes.Todo }, - ]); +describe("notesToSidebarNotes()", () => { + describe("unpinned notes only", () => { + it("returns notes in correct order", () => { + const notes: NotesObject = { + Todo: { + content: "my todo", + createdTime: "CT-TODO", + modifiedTime: "MT-TODO", + }, + Article: { + content: "my article", + createdTime: "CT-ARTICLE", + modifiedTime: "MT-ARTICLE", + }, + Shopping: { + content: "my shopping", + createdTime: "CT-SHOPPING", + modifiedTime: "MT-SHOPPING", + }, + }; + + const sidebarNotes = notesToSidebarNotes(notes, NotesOrder.Alphabetical); + expect(sidebarNotes).toEqual([ + { name: "Article", ...notes.Article }, + { name: "Shopping", ...notes.Shopping }, + { name: "Todo", ...notes.Todo }, + ]); + }); + }); + + describe("pinned and unpinned notes", () => { + it("returns notes in correct order", () => { + const notes: NotesObject = { + Todo: { + content: "my todo", + createdTime: "CT-TODO", + modifiedTime: "MT-3", + }, + Shopping: { + content: "my shopping", + createdTime: "CT-SHOPPING", + modifiedTime: "MT-9", + pinnedTime: "PT-SHOPPING", + }, + Article: { + content: "my article", + createdTime: "CT-ARTICLE", + modifiedTime: "MT-2", + }, + Clipboard: { + content: "my clipboard", + createdTime: "CT-CLIPBOARD", + modifiedTime: "MT-8", + pinnedTime: "PT-CLIPBOARD", + }, + }; + + const sidebarNotes = notesToSidebarNotes(notes, NotesOrder.Alphabetical); + expect(sidebarNotes).toEqual([ + { name: "Clipboard", ...notes.Clipboard }, + { name: "Shopping", ...notes.Shopping }, + + { name: "Article", ...notes.Article }, + { name: "Todo", ...notes.Todo }, + ]); + + const sidebarNotes2 = notesToSidebarNotes(notes, NotesOrder.NewestFirst); + expect(sidebarNotes2).toEqual([ + { name: "Shopping", ...notes.Shopping }, + { name: "Clipboard", ...notes.Clipboard }, + + { name: "Todo", ...notes.Todo }, + { name: "Article", ...notes.Article }, + ]); + + const sidebarNotes3 = notesToSidebarNotes(notes, NotesOrder.Custom, ["Shopping", "Article"]); + expect(sidebarNotes3).toEqual([ + { name: "Clipboard", ...notes.Clipboard }, + { name: "Shopping", ...notes.Shopping }, + + { name: "Todo", ...notes.Todo }, + { name: "Article", ...notes.Article }, + ]); + + const sidebarNotes4 = notesToSidebarNotes(notes, NotesOrder.Custom, []); + expect(sidebarNotes4).toEqual([ + { name: "Shopping", ...notes.Shopping }, + { name: "Clipboard", ...notes.Clipboard }, + + { name: "Todo", ...notes.Todo }, + { name: "Article", ...notes.Article }, + ]); + }); + }); }); diff --git a/src/notes/components/CommandPalette.tsx b/src/notes/components/CommandPalette.tsx index 8c54b533..43432553 100644 --- a/src/notes/components/CommandPalette.tsx +++ b/src/notes/components/CommandPalette.tsx @@ -1,12 +1,12 @@ import { h } from "preact"; import { useRef, useState, useMemo, useCallback, useEffect } from "preact/hooks"; -import { useBodyClass } from "notes/hooks/use-body-class"; -import { NotesObject } from "shared/storage/schema"; import clsx from "clsx"; +import { useBodyClass } from "notes/hooks/use-body-class"; +import { SidebarNote } from "notes/adapters"; import { t, tString } from "i18n"; export interface CommandPaletteProps { - notes: NotesObject + notes: SidebarNote[] commands: { name: string, translation: h.JSX.Element }[] onActivateNote: (noteName: string) => void onExecuteCommand: (commandName: string) => void @@ -56,9 +56,11 @@ export const prepareFilter = (rawInput: string): Filter => { }; }; -export const prepareItems = (notes: NotesObject, commands: string[], filter: Filter | undefined): string[] => { +export const prepareItems = (notes: SidebarNote[], commands: string[], filter: Filter | undefined): string[] => { + const noteNames = notes.map((note) => note.name); + if (!filter) { - return Object.keys(notes); // by default, list notes + return noteNames; } const input = filter.input.trim(); @@ -66,16 +68,22 @@ export const prepareItems = (notes: NotesObject, commands: string[], filter: Fil // A) CommandsByName if (filter.type === FilterType.CommandsByName) { - return commands.filter(prepareFilterPredicate(input)); // commands that include the input in their name + return commands.filter(prepareFilterPredicate(input)); } // B) NotesByContent if (filter.type === FilterType.NotesByContent) { - return input ? Object.keys(notes).filter((noteName) => prepareFilterPredicate(input)(notes[noteName].content)) : Object.keys(notes); // notes that include the input in their content + const filter = prepareFilterPredicate(input); + return input + ? noteNames.filter((noteName) => { + const foundNote = notes.find((note) => note.name === noteName); + return foundNote && filter(foundNote.content); + }) + : noteNames; } // C) NotesByName - return Object.keys(notes).filter(prepareFilterPredicate(input)); // notes that include the input in their name + return noteNames.filter(prepareFilterPredicate(input)); }; const CommandPalette = ({ notes, commands, onActivateNote, onExecuteCommand }: CommandPaletteProps): h.JSX.Element => { diff --git a/src/notes/components/__tests__/CommandPalette.test.tsx b/src/notes/components/__tests__/CommandPalette.test.tsx index 8e231cfe..6a693fcf 100644 --- a/src/notes/components/__tests__/CommandPalette.test.tsx +++ b/src/notes/components/__tests__/CommandPalette.test.tsx @@ -1,4 +1,4 @@ -import { NotesObject } from "shared/storage/schema"; +import { SidebarNote } from "notes/adapters"; import { Filter, FilterType, prepareFilter, prepareItems } from "../CommandPalette"; describe("prepareFilter", () => { @@ -38,23 +38,26 @@ describe("prepareItems", () => { const createdTime = "CT"; // not relevant for the test const modifiedTime = "MT"; // not relevant for the test - const notes: NotesObject = { - Clipboard: { + const notes: SidebarNote[] = [ + { + name: "Clipboard", content: "", createdTime, modifiedTime, }, - Article: { + { + name: "Article", content: "This is an interesting article", createdTime, modifiedTime, }, - TODO: { + { + name: "TODO", content: "buy milk, buy coffee", createdTime, modifiedTime, }, - }; + ]; const commands = [ "Insert current Date", diff --git a/src/notes/sort/index.ts b/src/notes/sort/index.ts index 89e8c931..f5e9b4d4 100644 --- a/src/notes/sort/index.ts +++ b/src/notes/sort/index.ts @@ -2,17 +2,35 @@ import { SidebarNote } from "notes/adapters"; import { NotesOrder } from "shared/storage/schema"; export const sortNotes = (notes: SidebarNote[], notesOrder: NotesOrder, custom?: string[]): SidebarNote[] => { + const pinnedNotes = notes.filter((note) => note.pinnedTime); + const unpinnedNotes = notes.filter((note) => !note.pinnedTime); + if (notesOrder === NotesOrder.Alphabetical) { - return notes.sort((a, b) => a.name.localeCompare(b.name)); + const alphabeticalCompare = (a: SidebarNote, b: SidebarNote) => a.name.localeCompare(b.name); + return [ + ...pinnedNotes.sort(alphabeticalCompare), + ...unpinnedNotes.sort(alphabeticalCompare), + ]; } if (notesOrder === NotesOrder.NewestFirst) { - return notes.sort((a, b) => -a.modifiedTime.localeCompare(b.modifiedTime)); + const newestFirstCompare = (a: SidebarNote, b: SidebarNote) => -a.modifiedTime.localeCompare(b.modifiedTime); + return [ + ...pinnedNotes.sort(newestFirstCompare), + ...unpinnedNotes.sort(newestFirstCompare), + ]; } if (custom?.length) { - return notes.sort((a, b) => custom.indexOf(a.name) - custom.indexOf(b.name)); + const customCompare = (a: SidebarNote, b: SidebarNote) => custom.indexOf(a.name) - custom.indexOf(b.name); + return [ + ...pinnedNotes.sort(customCompare), + ...unpinnedNotes.sort(customCompare), + ]; } - return notes; + return [ + ...pinnedNotes, + ...unpinnedNotes, + ]; }; From 5adf7619258e8edf4f4a48bbb38cb55d3f8d4ef5 Mon Sep 17 00:00:00 2001 From: penge Date: Wed, 25 May 2022 00:53:31 +0200 Subject: [PATCH 3/3] 3.21.1 --- manifest.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/manifest.json b/manifest.json index 62906229..20bd3620 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "My Notes", "description": "Simple and fast note-taking.", - "version": "3.21", + "version": "3.21.1", "homepage_url": "https://github.com/penge/my-notes", "icons": { "128": "images/icon128.png" diff --git a/package-lock.json b/package-lock.json index 177233bc..31f9160e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "my-notes", - "version": "3.21.0", + "version": "3.21.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "my-notes", - "version": "3.21.0", + "version": "3.21.1", "license": "MIT", "dependencies": { "clsx": "^1.1.1", diff --git a/package.json b/package.json index 5d410312..39738627 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-notes", - "version": "3.21.0", + "version": "3.21.1", "description": "Simple and fast note-taking.", "author": "Pavel Bucka", "license": "MIT",