mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-21 14:09:34 +01:00
Merge branch 'master' into beta
This commit is contained in:
@@ -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) =>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -183,7 +183,8 @@ function StatusBar() {
|
||||
sx={{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
display: "flex"
|
||||
display: "flex",
|
||||
height: "100%"
|
||||
}}
|
||||
data-test-id="vault-unlocked"
|
||||
>
|
||||
|
||||
@@ -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" }}
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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.
|
||||

|
||||
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.
|
||||

|
||||
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
|
||||
@@ -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]
|
||||
);
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -22,5 +22,5 @@ import { TemplateData } from "./index.js";
|
||||
export function buildText(data: TemplateData) {
|
||||
return `${data.title}
|
||||
|
||||
${data.content}`;
|
||||
${data.content}`;
|
||||
}
|
||||
|
||||
@@ -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 }] : [];
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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 }] : [];
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user