diff --git a/README.md b/README.md
index 00740cd..ad0dcce 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,13 @@
# 🚀 Getting started with PomeloNote
+### **THIS REPOSITORY HAS DEPENDENCIES WITH SECURITY VULNERABILITIES. YOU MIGHT WANT TO UPDATE PACKAGES BEFORE USE.**
+## Setup
+- run `npm i`
+- get the .env file and save it to the root directory of the project
+- set up Strapi
+ - go to `localhost:1337/admin`
+ - register an admin user
+ - go to Settings => Users&Permissions Plugin => Roles => Authenticated => Note => Select all
+ - Save
### Starting the container with svelte and strapi:
``docker-compose up --build -d``
diff --git a/backend/strapi/src/api/note/controllers/note.js b/backend/strapi/src/api/note/controllers/note.js
index 20de73a..84e7a8d 100644
--- a/backend/strapi/src/api/note/controllers/note.js
+++ b/backend/strapi/src/api/note/controllers/note.js
@@ -50,6 +50,9 @@ module.exports = createCoreController(noteUid, ({strapi}) => ({
lastViewed: Date.now()
}
})
+ entry = await strapi.entityService.findOne(noteUid, noteId, {
+ populate: ['owners'],
+ });
return JSON.stringify(entry);
} else {
ctx.response.status = 403;
@@ -63,22 +66,26 @@ module.exports = createCoreController(noteUid, ({strapi}) => ({
async update(ctx) {
const noteId = getNoteIdFromUrl(ctx.request.url)
const userId = ctx.state.user.id;
- const requestBody = ctx.request.body;
+ const requestBody = JSON.parse(ctx.request.body);
+ console.log(JSON.stringify(requestBody, null, 2))
const entry = await strapi.entityService.findOne(noteUid, noteId, {
populate: ['owners'],
});
const authorized = entry.owners.some(owner => owner.id === userId)
- let allPreviousOwnersKept = false;
+ let allPreviousOwnersKept = true;
if (requestBody.data.hasOwnProperty("owners")) {
allPreviousOwnersKept = entry.owners.every(owner => requestBody.data.owners.includes(owner));
}
+ console.log({
+ "auth": authorized,
+ "allprev": allPreviousOwnersKept,
+ })
if (!authorized) {
ctx.response.status = 403;
} else if (!allPreviousOwnersKept) {
ctx.response.status = 400;
- } else {
- return super.update(ctx);
}
+ return await strapi.entityService.update(noteUid, noteId, requestBody);
},
/**
* Creates a new note, automatically sets owners to the user making the request and lastViewed
@@ -87,7 +94,8 @@ module.exports = createCoreController(noteUid, ({strapi}) => ({
*/
async create(ctx) {
const userId = ctx.state.user.id;
- const requestBody = ctx.request.body;
+ const requestBody = JSON.parse(ctx.request.body);
+ console.log(requestBody);
const response = await strapi.entityService.create(noteUid, {
data: {
title: requestBody.data.title,
diff --git a/backend/strapi/src/extensions/users-permissions/content-types/user/schema.json b/backend/strapi/src/extensions/users-permissions/content-types/user/schema.json
new file mode 100644
index 0000000..7413352
--- /dev/null
+++ b/backend/strapi/src/extensions/users-permissions/content-types/user/schema.json
@@ -0,0 +1,73 @@
+{
+ "kind": "collectionType",
+ "collectionName": "up_users",
+ "info": {
+ "name": "user",
+ "description": "",
+ "singularName": "user",
+ "pluralName": "users",
+ "displayName": "User"
+ },
+ "options": {
+ "draftAndPublish": false,
+ "timestamps": true
+ },
+ "attributes": {
+ "username": {
+ "type": "string",
+ "minLength": 3,
+ "unique": true,
+ "configurable": false,
+ "required": true
+ },
+ "email": {
+ "type": "email",
+ "minLength": 6,
+ "configurable": false,
+ "required": true
+ },
+ "provider": {
+ "type": "string",
+ "configurable": false
+ },
+ "password": {
+ "type": "password",
+ "minLength": 6,
+ "configurable": false,
+ "private": true
+ },
+ "resetPasswordToken": {
+ "type": "string",
+ "configurable": false,
+ "private": true
+ },
+ "confirmationToken": {
+ "type": "string",
+ "configurable": false,
+ "private": true
+ },
+ "confirmed": {
+ "type": "boolean",
+ "default": false,
+ "configurable": false
+ },
+ "blocked": {
+ "type": "boolean",
+ "default": false,
+ "configurable": false
+ },
+ "role": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "plugin::users-permissions.role",
+ "inversedBy": "users",
+ "configurable": false
+ },
+ "notes": {
+ "type": "relation",
+ "relation": "manyToMany",
+ "target": "api::note.note",
+ "inversedBy": "owners"
+ }
+ }
+}
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000..2e92aba
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,3 @@
+remote_theme: pages-themes/leap-day@v0.2.0
+plugins:
+- jekyll-remote-theme
diff --git a/docs/_data/devs.csv b/docs/_data/devs.csv
new file mode 100644
index 0000000..5c60b6c
--- /dev/null
+++ b/docs/_data/devs.csv
@@ -0,0 +1,4 @@
+name,github,image
+Jonas Weissengruber,j-weissen,jowei
+Stefan Prechtler,s-prechtl,stef
+David Hain,d-hain,dave
\ No newline at end of file
diff --git a/docs/images/dave.jpg b/docs/images/dave.jpg
new file mode 100644
index 0000000..9fe6268
Binary files /dev/null and b/docs/images/dave.jpg differ
diff --git a/docs/images/delete.png b/docs/images/delete.png
new file mode 100644
index 0000000..39ae1b5
Binary files /dev/null and b/docs/images/delete.png differ
diff --git a/docs/images/editor.png b/docs/images/editor.png
new file mode 100644
index 0000000..690ef69
Binary files /dev/null and b/docs/images/editor.png differ
diff --git a/docs/images/jowei.jpg b/docs/images/jowei.jpg
new file mode 100644
index 0000000..6785c8d
Binary files /dev/null and b/docs/images/jowei.jpg differ
diff --git a/docs/images/listing.png b/docs/images/listing.png
new file mode 100644
index 0000000..8b1189b
Binary files /dev/null and b/docs/images/listing.png differ
diff --git a/docs/images/login.png b/docs/images/login.png
new file mode 100644
index 0000000..e9c1cbd
Binary files /dev/null and b/docs/images/login.png differ
diff --git a/docs/images/register.png b/docs/images/register.png
new file mode 100644
index 0000000..68336c8
Binary files /dev/null and b/docs/images/register.png differ
diff --git a/docs/images/stef.jpg b/docs/images/stef.jpg
new file mode 100644
index 0000000..231d3e3
Binary files /dev/null and b/docs/images/stef.jpg differ
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..7c87e05
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,31 @@
+# Pomelo Note
+
+This is the best open source note app you will ever find.
+
+## Login
+When first entering the app, you will need to login. If you haven't got an account you may consider [registering](#register), or just not using the app at all.
+
+
+## Register
+A username, an email and a password that's all you need. If you are missing one of those, just don't use the app at all.
+
+
+## Editor
+You can edit your notes with our minimalistic editor interface.
+
+
+## Listing
+Here you can see all your notes. Click on them to open the editor or hover and press the red "X" to delete them.
+
+
+## Delete
+Confirm the deletion.
+
+
+# The Team
+{% for dev in site.data.devs %}
+ {{ dev.name }}
+ [GitHub](https://github.com/{{ dev.github }})
+ 
+{% endfor %}
+
diff --git a/frontend/svelte/package-lock.json b/frontend/svelte/package-lock.json
index 63551ad..d5c5126 100644
--- a/frontend/svelte/package-lock.json
+++ b/frontend/svelte/package-lock.json
@@ -9,7 +9,9 @@
"version": "0.0.1",
"dependencies": {
"bootstrap-icons": "^1.9.1",
- "nookies": "^2.5.2"
+ "nookies": "^2.5.2",
+ "sv-popup": "^0.2.5",
+ "webworker": "^0.8.4"
},
"devDependencies": {
"@sveltejs/adapter-auto": "next",
@@ -2083,6 +2085,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/sv-popup": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/sv-popup/-/sv-popup-0.2.5.tgz",
+ "integrity": "sha512-JhBu4piXaauamT4vMEcFCydvxJ8e72G7c9F3caZVAPsiFqWPTYT3JDz99FlR+YCnbOp1emsZqqOPVvCwHgURog=="
+ },
"node_modules/svelte": {
"version": "3.50.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.50.1.tgz",
@@ -2358,6 +2365,14 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"dev": true
},
+ "node_modules/webworker": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/webworker/-/webworker-0.8.4.tgz",
+ "integrity": "sha512-zzsVxtHf+mCn0WuYLarSWfRGmX7JiYKkKvso5FYC7rJ9G8svwGQA5a51Sjq9D2c/rKVU6U/kyBcaI7gUTVlsJg==",
+ "engines": {
+ "node": ">=0.4.3"
+ }
+ },
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@@ -3824,6 +3839,11 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
+ "sv-popup": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/sv-popup/-/sv-popup-0.2.5.tgz",
+ "integrity": "sha512-JhBu4piXaauamT4vMEcFCydvxJ8e72G7c9F3caZVAPsiFqWPTYT3JDz99FlR+YCnbOp1emsZqqOPVvCwHgURog=="
+ },
"svelte": {
"version": "3.50.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.50.1.tgz",
@@ -3981,6 +4001,11 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"dev": true
},
+ "webworker": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/webworker/-/webworker-0.8.4.tgz",
+ "integrity": "sha512-zzsVxtHf+mCn0WuYLarSWfRGmX7JiYKkKvso5FYC7rJ9G8svwGQA5a51Sjq9D2c/rKVU6U/kyBcaI7gUTVlsJg=="
+ },
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
diff --git a/frontend/svelte/package.json b/frontend/svelte/package.json
index 7ea33f8..81a0887 100644
--- a/frontend/svelte/package.json
+++ b/frontend/svelte/package.json
@@ -22,7 +22,9 @@
},
"type": "module",
"dependencies": {
+ "bootstrap-icons": "^1.9.1",
"nookies": "^2.5.2",
- "bootstrap-icons": "^1.9.1"
+ "sv-popup": "^0.2.5",
+ "webworker": "^0.8.4"
}
}
diff --git a/frontend/svelte/src/app.html b/frontend/svelte/src/app.html
index 2767694..9d5ca24 100644
--- a/frontend/svelte/src/app.html
+++ b/frontend/svelte/src/app.html
@@ -1,12 +1,13 @@
-
+
+
%sveltekit.head%
%sveltekit.body%
-
+
\ No newline at end of file
diff --git a/frontend/svelte/src/customBootstrap.css b/frontend/svelte/src/customBootstrap.css
new file mode 100644
index 0000000..311d8a4
--- /dev/null
+++ b/frontend/svelte/src/customBootstrap.css
@@ -0,0 +1,29 @@
+
+html,
+:root {
+ --main-txt-color: black;
+ --cross-txt-color: red;
+
+ --color-primary: #fff494;
+ --color-primary-600: #fff17a;
+ --color-primary-700: #ffec47;
+ --color-primary-800: #ffe714;
+ --color-primary-900: #e0c900;
+}
+
+.btn-primary {
+ background-color: var(--color-primary-800) !important;
+ border: var(--color-primary-800) !important;
+ color: var(--main-txt-color) !important;
+}
+
+.btn-primary:hover {
+ background-color: var(--color-primary-900) !important;
+ border: var(--color-primary-900) !important;
+ color: var(--main-txt-color) !important;
+}
+
+.btn-primary:disabled {
+ background-color: var(--color-primary-700) !important;
+ border: var(--color-primary-700) !important;
+}
\ No newline at end of file
diff --git a/frontend/svelte/src/models/PomeloUtils.ts b/frontend/svelte/src/models/PomeloUtils.ts
index 5d290ae..cfec11b 100644
--- a/frontend/svelte/src/models/PomeloUtils.ts
+++ b/frontend/svelte/src/models/PomeloUtils.ts
@@ -1,4 +1,5 @@
-import {parseCookies} from "nookies";
+import type {Authentication} from "./authentication";
+import {createErrorToast} from "./customToasts";
/**
* Capitalises first letter of string.
@@ -22,13 +23,14 @@ export async function bearerFetch(endpoint: string, jwt: string, baseUrl: string
});
}
-
-const getJwtCookie = () => {
- // @ts-ignore
- return parseCookies("/").jwt;
-};
-
-/**
- * JWT Cookie
- */
-export const jwt: string = getJwtCookie();
\ No newline at end of file
+export function handleErrorsFromResponseWithToast(response: Authentication) {
+ if (response.error != null) {
+ if (response.error.details.errors) {
+ for (const error of response.error.details.errors) {
+ createErrorToast(error.message);
+ }
+ } else {
+ createErrorToast(response.error.message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/svelte/src/routes/login/models/authentication.ts b/frontend/svelte/src/models/authentication.ts
similarity index 70%
rename from frontend/svelte/src/routes/login/models/authentication.ts
rename to frontend/svelte/src/models/authentication.ts
index dccb434..c5adc10 100644
--- a/frontend/svelte/src/routes/login/models/authentication.ts
+++ b/frontend/svelte/src/models/authentication.ts
@@ -1,4 +1,4 @@
-import type {User} from "../../../models/user";
+import type {User} from "./user";
/**
* User Login Auth.
diff --git a/frontend/svelte/src/models/NoteRepository.ts b/frontend/svelte/src/models/repos/note/NoteRepository.ts
similarity index 89%
rename from frontend/svelte/src/models/NoteRepository.ts
rename to frontend/svelte/src/models/repos/note/NoteRepository.ts
index c83d5a6..84b6705 100644
--- a/frontend/svelte/src/models/NoteRepository.ts
+++ b/frontend/svelte/src/models/repos/note/NoteRepository.ts
@@ -1,4 +1,4 @@
-import type {Note} from "./types";
+import type {Note} from "../../types";
export interface NoteRepository {
getNotes(): Promise;
diff --git a/frontend/svelte/src/models/StrapiNoteRepository.ts b/frontend/svelte/src/models/repos/note/StrapiNoteRepository.ts
similarity index 76%
rename from frontend/svelte/src/models/StrapiNoteRepository.ts
rename to frontend/svelte/src/models/repos/note/StrapiNoteRepository.ts
index 760edbd..4043bbf 100644
--- a/frontend/svelte/src/models/StrapiNoteRepository.ts
+++ b/frontend/svelte/src/models/repos/note/StrapiNoteRepository.ts
@@ -1,6 +1,8 @@
-import type {Note} from "./types";
+import type {Note} from "../../types";
import {parseCookies} from "nookies";
import type {NoteRepository} from "./NoteRepository";
+import {currentNoteId} from "../../../stores";
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
@@ -13,11 +15,21 @@ export class StrapiNoteRepository implements NoteRepository {
return this.instance;
}
- private constructor() {}
+ private constructor() {
+ currentNoteId.subscribe((value) => (this._currentNoteId = value));
+ }
- private currentNoteId: number | undefined;
+ private _currentNoteId: unknown;
private static apiNoteEndpoint: string = "http://localhost:1337/api/notes"
+ public set currentNoteId(value: number | undefined) {
+ currentNoteId.set(value || -1);
+ }
+
+ public get currentNoteId(): number {
+ return this._currentNoteId;
+ }
+
public async getNotes(): Promise{
const response = await StrapiNoteRepository.fetchStrapiNoteEndpoint("/", 'GET');
return await response.json();
@@ -29,7 +41,7 @@ export class StrapiNoteRepository implements NoteRepository {
}
public async getCurrentNote(): Promise {
- if (this.currentNoteId === null || this.currentNoteId === undefined) {
+ if (this._currentNoteId === null || this._currentNoteId === undefined) {
return;
}
return await this.getNote(this.currentNoteId);
@@ -53,7 +65,7 @@ export class StrapiNoteRepository implements NoteRepository {
let requestInit: RequestInit = {
method: method,
headers: {
- authorization: StrapiNoteRepository.mockedGetAuthorizationHeader()
+ authorization: StrapiNoteRepository.getAuthorizationHeader()
}
};
if (body) {
@@ -66,8 +78,9 @@ export class StrapiNoteRepository implements NoteRepository {
return "bearer TOKEN"
}
- private static getAuthorizationHeader() {
- const jwt = parseCookies().jwt;
+ static getAuthorizationHeader() {
+ // @ts-ignore
+ const jwt = parseCookies('/').jwt;
return `bearer ${jwt}`
}
}
\ No newline at end of file
diff --git a/frontend/svelte/src/models/repos/user/StrapiUserRepo.ts b/frontend/svelte/src/models/repos/user/StrapiUserRepo.ts
new file mode 100644
index 0000000..58f2ea2
--- /dev/null
+++ b/frontend/svelte/src/models/repos/user/StrapiUserRepo.ts
@@ -0,0 +1,93 @@
+import type {UserRepository} from "./UserRepository";
+import type {Authentication} from "../../authentication";
+import type {HttpMethod} from "@sveltejs/kit/types/private";
+import {StrapiNoteRepository} from "../note/StrapiNoteRepository";
+import {error} from "@sveltejs/kit";
+import {User} from "../../user";
+
+export class StrapiUserRepo implements UserRepository {
+ private static instance: StrapiUserRepo;
+
+ public static getInstance(verification: boolean = true): StrapiUserRepo {
+ if (this.instance === undefined || this.instance === null) {
+ this.instance = new StrapiUserRepo();
+ this.instance.verify().then(() => {
+ if (verification && !this.instance.verified) {
+ window.location.href = "/login";
+ }
+ });
+ }
+ return this.instance;
+ }
+
+ private verified: boolean = false;
+
+ private constructor() {
+ }
+
+ private static api: string = "http://localhost:1337/api"
+
+ private static apiUserEndpoint: string = StrapiUserRepo.api + "/auth/local"
+
+ /**
+ * Verifies the current users jwt.
+ * @private
+ */
+ private async verify() {
+ this.verified = false;
+ let result = await this.getMe();
+ if (!result.error) {
+ this.verified = true;
+ }
+ }
+
+ async getMe(): Promise {
+ const response = await StrapiUserRepo.fetchStrapi("/me", "GET", null, true, "/users")
+ return await response.json();
+ }
+
+ async registerUser(email: string, username: string, password: string): Promise {
+ const payload = {
+ email: email,
+ password: password,
+ username: username
+ };
+ const response = await StrapiUserRepo.fetchStrapi("/register", "POST", payload, false);
+ return await response.json();
+ }
+
+ async loginUser(identifier: string, password: string): Promise {
+ const payload = {
+ identifier: identifier,
+ password: password
+ };
+ const response = await StrapiUserRepo.fetchStrapi("/", "POST", payload, false);
+ return response.json();
+ }
+
+ private static async fetchStrapi(path: string, method: HttpMethod, body: any | null = null, authorization: boolean = true, customPath: any = null): Promise {
+ let requestInit: RequestInit = {
+ method: method,
+ };
+ if (authorization && body) {
+ requestInit["headers"] = {
+ authorization: StrapiNoteRepository.getAuthorizationHeader() ?? '',
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ }
+ } else if (authorization) {
+ requestInit["headers"] = {
+ authorization: StrapiNoteRepository.getAuthorizationHeader() ?? '',
+ }
+ } else if (body) {
+ requestInit["headers"] = {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ }
+ }
+ if (body) {
+ requestInit["body"] = JSON.stringify(body)
+ }
+ return await fetch((customPath) ? (this.api + customPath + path) : StrapiUserRepo.apiUserEndpoint + path, requestInit);
+ }
+}
\ No newline at end of file
diff --git a/frontend/svelte/src/models/repos/user/UserRepository.ts b/frontend/svelte/src/models/repos/user/UserRepository.ts
new file mode 100644
index 0000000..3128bfb
--- /dev/null
+++ b/frontend/svelte/src/models/repos/user/UserRepository.ts
@@ -0,0 +1,19 @@
+import type {Authentication} from "../../authentication";
+
+export interface UserRepository {
+ /**
+ * Registers a new user.
+ * @param email
+ * @param username
+ * @param password
+ */
+ registerUser(email: string, username: string, password: string): Promise;
+
+ /**
+ * Gets the current user.
+ * @param jwt
+ */
+ getMe(jwt: string): Promise;
+
+ loginUser(identifier: string, password: string): Promise;
+}
\ No newline at end of file
diff --git a/frontend/svelte/src/resources/icons/android-icon-144x144.png b/frontend/svelte/src/resources/icons/android-icon-144x144.png
new file mode 100644
index 0000000..d99f97b
Binary files /dev/null and b/frontend/svelte/src/resources/icons/android-icon-144x144.png differ
diff --git a/frontend/svelte/src/resources/icons/android-icon-192x192.png b/frontend/svelte/src/resources/icons/android-icon-192x192.png
new file mode 100644
index 0000000..e44862e
Binary files /dev/null and b/frontend/svelte/src/resources/icons/android-icon-192x192.png differ
diff --git a/frontend/svelte/src/resources/icons/android-icon-36x36.png b/frontend/svelte/src/resources/icons/android-icon-36x36.png
new file mode 100644
index 0000000..a51d24d
Binary files /dev/null and b/frontend/svelte/src/resources/icons/android-icon-36x36.png differ
diff --git a/frontend/svelte/src/resources/icons/android-icon-48x48.png b/frontend/svelte/src/resources/icons/android-icon-48x48.png
new file mode 100644
index 0000000..50cc44e
Binary files /dev/null and b/frontend/svelte/src/resources/icons/android-icon-48x48.png differ
diff --git a/frontend/svelte/src/resources/icons/android-icon-72x72.png b/frontend/svelte/src/resources/icons/android-icon-72x72.png
new file mode 100644
index 0000000..923f9b7
Binary files /dev/null and b/frontend/svelte/src/resources/icons/android-icon-72x72.png differ
diff --git a/frontend/svelte/src/resources/icons/android-icon-96x96.png b/frontend/svelte/src/resources/icons/android-icon-96x96.png
new file mode 100644
index 0000000..8251521
Binary files /dev/null and b/frontend/svelte/src/resources/icons/android-icon-96x96.png differ
diff --git a/frontend/svelte/src/routes/+page.svelte b/frontend/svelte/src/routes/+page.svelte
index f52d418..e744ac0 100644
--- a/frontend/svelte/src/routes/+page.svelte
+++ b/frontend/svelte/src/routes/+page.svelte
@@ -1,87 +1,48 @@
-
+
PomeloNote | Home
-
+
+
-
+
@@ -141,18 +114,42 @@
onNoteLiClick(note)}>
- {note.attributes.title}
+ {note.title}
- {note.attributes.lastViewed.toLocaleDateString()}
+ {note.lastViewed.toLocaleDateString()}
-
+
+
+
+
+
Do you really want to delete the "{note.title}" note?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -166,17 +163,11 @@
diff --git a/frontend/svelte/src/routes/login/+page.svelte b/frontend/svelte/src/routes/login/+page.svelte
index fee4156..537507d 100644
--- a/frontend/svelte/src/routes/login/+page.svelte
+++ b/frontend/svelte/src/routes/login/+page.svelte
@@ -1,9 +1,9 @@