Merge branch 'master' into beta

This commit is contained in:
Abdullah Atta
2025-10-02 10:40:56 +05:00
14 changed files with 156 additions and 14 deletions

View File

@@ -71,7 +71,7 @@ async function initializeDatabase(persistence: DatabasePersistence) {
);
await storage.migrate();
const multiTab = isFeatureSupported("opfs");
const multiTab = !!globalThis.SharedWorker && isFeatureSupported("opfs");
database.setup({
sqliteOptions: {
dialect: (name, init) =>

View File

@@ -247,7 +247,7 @@ function errorToString(error: unknown) {
}
async function resetDatabase() {
const multiTab = isFeatureSupported("opfs");
const multiTab = !!globalThis.SharedWorker && isFeatureSupported("opfs");
await useKeyStore.getState().clear();
const dialect = createDialect({
name: "notesnook",

View File

@@ -183,7 +183,8 @@ function StatusBar() {
sx={{
alignItems: "center",
justifyContent: "center",
display: "flex"
display: "flex",
height: "100%"
}}
data-test-id="vault-unlocked"
>

View File

@@ -136,8 +136,11 @@ export function SubscriptionStatus() {
type: "modal",
title: strings.redeemingGiftCode(),
subtitle: strings.pleaseWait() + "...",
action: () => db.subscriptions.redeemCode(giftCode)
}).catch((e) => showToast("error", e.message));
action: () =>
db.subscriptions
.redeemCode(giftCode)
.catch((e) => showToast("error", e.message))
});
}
}}
sx={{ bg: "background" }}

View File

@@ -27,7 +27,7 @@ import { isFeatureSupported } from "./feature-check";
let logger: typeof _logger = new NoopLogger();
async function initializeLogger() {
const multiTab = isFeatureSupported("opfs");
const multiTab = !!globalThis.SharedWorker && isFeatureSupported("opfs");
await initialize(
{
dialect: (name, init) =>

View File

@@ -0,0 +1,23 @@
---
title: Standard Notes
---
# How do I import notes from Standard Notes?
The following steps will help you import your notes from Standard notes easily.
1. Open Standard Notes app on Desktop or visit [https://app.standardnotes.org](https://app.standardnotes.org) and login to your account.
2. Select all your notes, right click, and select `Export`.
3. Open the Notesnook (app or desktop).
4. Go to `Settings > Notesnook Importer` and select `Standard Notes` from list of apps.
![](/static/standard-notes-importer/3.png)
5. Drop the .zip file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup.
![](/static/standard-notes-importer/4.png)
6. Once importing completes you should see all your notes in Notesnook. If you face any issues during importing, [report it on github](https://github.com/streetwriters/notesnook).
## Supported formats
- [x] Text files
- [x] Authentication notes
- [x] Spreadsheets
- [ ] Tags

View File

@@ -18,10 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { databaseTest, noteTest, TEST_NOTE } from "./utils/index.js";
import { test, expect } from "vitest";
import { test, expect, describe } from "vitest";
function tag(title: string) {
return { title };
function tag(title: string, dateCreated?: number) {
return { title, dateCreated };
}
function color(title: string) {
@@ -98,3 +98,50 @@ for (const type of ["tag", "color"] as const) {
);
}));
}
describe("sort tags by", () => {
const tags = ["apple", "mango", "melon", "orange", "zucchini"];
const sortTestCases = [
{
sortBy: "title",
sortDirection: "asc",
expectedOrder: ["apple", "mango", "melon", "orange", "zucchini"]
},
{
sortBy: "title",
sortDirection: "desc",
expectedOrder: ["zucchini", "orange", "melon", "mango", "apple"]
},
{
sortBy: "dateCreated",
sortDirection: "asc",
expectedOrder: ["apple", "mango", "melon", "orange", "zucchini"]
},
{
sortBy: "dateCreated",
sortDirection: "desc",
expectedOrder: ["zucchini", "orange", "melon", "mango", "apple"]
}
] as const;
for (const testCase of sortTestCases) {
test(`${testCase.sortBy} ${testCase.sortDirection}`, () =>
databaseTest().then(async (db) => {
let previousCreatedDate = Date.now();
for (const title of tags) {
await db.tags.add(tag(title, previousCreatedDate++));
}
const items = await db.tags.all.grouped({
sortBy: testCase.sortBy,
sortDirection: testCase.sortDirection,
groupBy: "default"
});
for (let i = 0; i < testCase.expectedOrder.length; i++) {
expect((await items.item(i)).item?.title).toEqual(
testCase.expectedOrder[i]
);
}
}));
}
});

View File

@@ -126,6 +126,16 @@ But this post was supposed to be about the "Secrets" of Typescript Generics, rig
"
`;
exports[`convert HTML to markdown with leadingWhitespaces > html-to-md-leadingWhitespaces.md 1`] = `
"two spaces
four spaces
two spaces
four spaces
"
`;
exports[`convert HTML to markdown with outlinelists > html-to-md-outlinelists.md 1`] = `
"Testing outline list:
@@ -389,6 +399,14 @@ right? Well, let's get into that.
4. TYPE INFERENCE USING INTERFACE PROPERTIES"
`;
exports[`convert HTML to text with leadingWhitespaces > html-to-txt-leadingWhitespaces.txt 1`] = `
"  two spaces
    four spaces
  two spaces
    four spaces"
`;
exports[`convert HTML to text with outlinelists > html-to-txt-outlinelists.txt 1`] = `
"Testing outline list:
* My outline list

View File

@@ -65,7 +65,8 @@ const HTMLS = {
tasklists: `<p>Hello</p><ul data-collapsed="false" class="checklist"><li class="checked checklist--item"><p>Task item 1</p></li><li class="checked checklist--item"><p>Task item 2</p></li><li class="checked checklist--item"><p>Task item 3</p></li><li class="checklist--item"><p>Task item 4</p><ul data-collapsed="false" class="checklist"><li class="checklist--item"><p>Sub task item 1</p></li><li class="checklist--item"><p>Sub task item 2</p></li></ul></li><li class="checklist--item"><p>Task Item 5</p></li></ul><p>Nene</p><ul><li><p>dasvsadv</p></li><li><p>adsva\`sd</p></li><li><p>vasd</p></li><li><p>vsadvdsa</p></li></ul>`,
outlinelists: `<p >Testing outline list:</p><ul data-collapsed="false" data-type="outlineList"><li data-type="outlineListItem"><p >My outline list</p></li><li data-type="outlineListItem"><p >works</p></li><li data-type="outlineListItem"><p >but sometimes</p><ul data-collapsed="false" data-type="outlineList"><li data-type="outlineListItem"><p >It doesn't</p></li><li data-type="outlineListItem"><p >what do I do?</p></li><li data-type="outlineListItem"><p >I need to do something!</p></li></ul></li><li data-type="outlineListItem"><p >Makes no sense!</p></li><li data-type="outlineListItem"><p >Yes it doesn't!</p></li></ul>`,
codeblock2: `<pre>hello<br></pre>`,
singleSpacedParagraphs: `<p data-spacing="single">hello world</p><p data-spacing="single">hello world 2</p>`
singleSpacedParagraphs: `<p data-spacing="single">hello world</p><p data-spacing="single">hello world 2</p>`,
leadingWhitespaces: `<p data-spacing="double"> two spaces</p><p data-spacing="double"> four spaces</p><p data-spacing="single"> two spaces</p><p data-spacing="single"> four spaces</p>`
};
for (const html in HTMLS) {

View File

@@ -413,6 +413,22 @@ function convertHtmlToTxt(html: string, wrap = true) {
builder.openBlock({
leadingLineBreaks: dataSpacing == "single" ? 1 : 2
});
// convert leading whitespace to NO-BREAK SPACE
if (elem.children && elem.children.length > 0) {
const firstChild = elem.children[0];
if (firstChild.type === "text" && firstChild.data) {
firstChild.data = firstChild.data.replace(
/^([ \t]+)/,
(match) => {
return match
.replace(/ /g, "\u00A0")
.replace(/\t/g, "\u00A0\u00A0\u00A0\u00A0");
}
);
}
}
walk(elem.children, builder);
builder.closeBlock({
trailingLineBreaks: 1

View File

@@ -609,10 +609,10 @@ export class FilteredSelector<T extends Item> {
sanitizeSortOptions(this.type, options);
const sortBy: Set<SortOptions["sortBy"]> = new Set();
sortBy.add(options.sortBy);
if (options.groupBy === "abc") sortBy.add("title");
else if (options.sortBy === "title" && options.groupBy !== "none")
sortBy.add("dateCreated");
sortBy.add(options.sortBy);
return <T>(
qb: SelectQueryBuilder<DatabaseSchema, keyof DatabaseSchema, T>

View File

@@ -22,5 +22,5 @@ import { TemplateData } from "./index.js";
export function buildText(data: TemplateData) {
return `${data.title}
${data.content}`;
${data.content}`;
}

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Node, mergeAttributes } from "@tiptap/core";
import { Node, mergeAttributes, nodePasteRule } from "@tiptap/core";
import { insertMathNode } from "./plugin/index.js";
import { NodeSelection } from "prosemirror-state";
import { tiptapKeys } from "@notesnook/common";
@@ -32,6 +32,8 @@ declare module "@tiptap/core" {
// simple inputrule for block math
const REGEX_BLOCK_MATH_DOLLARS = /\$\$\$\s+$/; //new RegExp("\$\$\s+$", "i");
const REGEX_PASTE_BLOCK_MATH_DOLLARS = /\$\$\$([\s\S]*?)\$\$\$/g;
export const MathBlock = Node.create({
name: "mathBlock",
group: "block math",
@@ -99,5 +101,20 @@ export const MathBlock = Node.create({
}
}
];
},
addPasteRules() {
return [
nodePasteRule({
find: REGEX_PASTE_BLOCK_MATH_DOLLARS,
type: this.type,
getAttributes: (match) => {
return { content: match[1] };
},
getContent: (attrs) => {
return attrs.content ? [{ type: "text", text: attrs.content }] : [];
}
})
];
}
});

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Node, mergeAttributes } from "@tiptap/core";
import { Node, mergeAttributes, nodePasteRule } from "@tiptap/core";
import { mathPlugin } from "./plugin/index.js";
declare module "@tiptap/core" {
@@ -40,6 +40,7 @@ const REGEX_INLINE_MATH_DOLLARS = /\$\$(.+)\$\$/; //new RegExp("\$(.+)\$", "i");
// return REGEX_INLINE_MATH_DOLLARS;
// }
// })();
const REGEX_PASTE_INLINE_MATH_DOLLARS = /\$\$([\s\S]*?)\$\$/g;
export const MathInline = Node.create({
name: "mathInline",
@@ -107,5 +108,20 @@ export const MathInline = Node.create({
}
}
];
},
addPasteRules() {
return [
nodePasteRule({
find: REGEX_PASTE_INLINE_MATH_DOLLARS,
type: this.type,
getAttributes: (match) => {
return { content: match[1] };
},
getContent: (attrs) => {
return attrs.content ? [{ type: "text", text: attrs.content }] : [];
}
})
];
}
});