Merge branch 'develop' into user-repo
# Conflicts: # frontend/svelte/src/routes/+page.svelte # frontend/svelte/src/routes/login/+page.svelte
This commit is contained in:
commit
bee5b04441
20 changed files with 197 additions and 154 deletions
|
|
@ -22,7 +22,8 @@
|
||||||
"owners": {
|
"owners": {
|
||||||
"type": "relation",
|
"type": "relation",
|
||||||
"relation": "manyToMany",
|
"relation": "manyToMany",
|
||||||
"target": "plugin::users-permissions.user"
|
"target": "plugin::users-permissions.user",
|
||||||
|
"mappedBy": "notes"
|
||||||
},
|
},
|
||||||
"lastViewed": {
|
"lastViewed": {
|
||||||
"type": "datetime",
|
"type": "datetime",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
//move to utils!
|
//move to utils!
|
||||||
|
|
||||||
function getNoteIdFromUrl(url) {
|
function getNoteIdFromUrl(url) {
|
||||||
return Number(url.split("/").at(-1));
|
return Number(url.split("/").at(-1));
|
||||||
}
|
}
|
||||||
|
|
@ -43,7 +44,6 @@ module.exports = createCoreController(noteUid, ({strapi}) => ({
|
||||||
populate: ['owners'],
|
populate: ['owners'],
|
||||||
});
|
});
|
||||||
const authorized = entry.owners.some(owner => owner.id === userId)
|
const authorized = entry.owners.some(owner => owner.id === userId)
|
||||||
console.log(authorized)
|
|
||||||
if (authorized) {
|
if (authorized) {
|
||||||
entry = await strapi.entityService.update(noteUid, noteId, {
|
entry = await strapi.entityService.update(noteUid, noteId, {
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -68,18 +68,38 @@ module.exports = createCoreController(noteUid, ({strapi}) => ({
|
||||||
populate: ['owners'],
|
populate: ['owners'],
|
||||||
});
|
});
|
||||||
const authorized = entry.owners.some(owner => owner.id === userId)
|
const authorized = entry.owners.some(owner => owner.id === userId)
|
||||||
let allowed;
|
let allPreviousOwnersKept = false;
|
||||||
if (requestBody.data.hasOwnProperty("owners")) {
|
if (requestBody.data.hasOwnProperty("owners")) {
|
||||||
allowed = entry.owners.every(owner => requestBody.data.owners.includes(owner));
|
allPreviousOwnersKept = entry.owners.every(owner => requestBody.data.owners.includes(owner));
|
||||||
}
|
}
|
||||||
if (!authorized) {
|
if (!authorized) {
|
||||||
ctx.response.status = 403;
|
ctx.response.status = 403;
|
||||||
} else if (!allowed) {
|
} else if (!allPreviousOwnersKept) {
|
||||||
ctx.response.status = 400;
|
ctx.response.status = 400;
|
||||||
} else {
|
} else {
|
||||||
return super.update(ctx);
|
return super.update(ctx);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Creates a new note, automatically sets owners to the user making the request and lastViewed
|
||||||
|
* @param ctx
|
||||||
|
* @returns {Promise<ctx>}
|
||||||
|
*/
|
||||||
|
async create(ctx) {
|
||||||
|
const userId = ctx.state.user.id;
|
||||||
|
const requestBody = JSON.parse(ctx.request.body);
|
||||||
|
console.log(requestBody);
|
||||||
|
const response = await strapi.entityService.create(noteUid, {
|
||||||
|
data: {
|
||||||
|
title: requestBody.data.title,
|
||||||
|
content: requestBody.data.content,
|
||||||
|
lastViewed: Date.now(),
|
||||||
|
owners: [userId],
|
||||||
|
publishedAt: Date.now()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Deletes user from note owners. If note has no owners anymore, deletes note.
|
* Deletes user from note owners. If note has no owners anymore, deletes note.
|
||||||
* @param ctx
|
* @param ctx
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,16 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="../src/resources/images/logo2.svg" />
|
<link rel="icon" href="../src/resources/images/logo2.svg" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<link rel="manifest" href="../static/manifest.json">
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div>%sveltekit.body%</div>
|
<div>%sveltekit.body%</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
if('serviceworker' in navigator){
|
||||||
|
navigator.serviceworker.register('./service-worker.js');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
29
frontend/svelte/src/customBootstrap.css
Normal file
29
frontend/svelte/src/customBootstrap.css
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ export interface NoteRepository {
|
||||||
getNotes(): Promise<Note[]>;
|
getNotes(): Promise<Note[]>;
|
||||||
getNote(id: number): Promise<Note>;
|
getNote(id: number): Promise<Note>;
|
||||||
getCurrentNote(): Promise<Note | void>;
|
getCurrentNote(): Promise<Note | void>;
|
||||||
updateNote(id: number, note: Note): Promise<Note>;
|
updateNote(id: number, note: Partial<Note>): Promise<Note>;
|
||||||
deleteNote(id: number): void;
|
deleteNote(id: number): void;
|
||||||
createNote(note: Note): Promise<Note>;
|
createNote(note: Partial<Note> & Pick<Note, 'title'>): Promise<Note>;
|
||||||
}
|
}
|
||||||
|
|
@ -15,45 +15,49 @@ export class StrapiNoteRepository implements NoteRepository {
|
||||||
|
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
||||||
private currentNoteId: number | undefined;
|
private _currentNoteId: number | undefined;
|
||||||
private static apiNoteEndpoint: string = "http://localhost:1337/api/notes"
|
private static apiNoteEndpoint: string = "http://localhost:1337/api/notes"
|
||||||
|
|
||||||
|
public set currentNoteId(value: number | undefined) {
|
||||||
|
this._currentNoteId = value;
|
||||||
|
}
|
||||||
|
|
||||||
public async getNotes(): Promise<Note[]>{
|
public async getNotes(): Promise<Note[]>{
|
||||||
const response = await StrapiNoteRepository.fetchStrapi("/", 'GET');
|
const response = await StrapiNoteRepository.fetchStrapiNoteEndpoint("/", 'GET');
|
||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getNote(id: number): Promise<Note>{
|
public async getNote(id: number): Promise<Note>{
|
||||||
const response = await StrapiNoteRepository.fetchStrapi("/" + id, 'GET');
|
const response = await StrapiNoteRepository.fetchStrapiNoteEndpoint("/" + id, 'GET');
|
||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getCurrentNote(): Promise<Note | void> {
|
public async getCurrentNote(): Promise<Note | void> {
|
||||||
if (this.currentNoteId === null || this.currentNoteId === undefined) {
|
if (this._currentNoteId === null || this._currentNoteId === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return await this.getNote(this.currentNoteId);
|
return await this.getNote(this._currentNoteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateNote(id: number, note: Note): Promise<Note> {
|
public async updateNote(id: number, note: Partial<Note>): Promise<Note> {
|
||||||
const response = await StrapiNoteRepository.fetchStrapi("/" + id, 'PUT', note);
|
const response = await StrapiNoteRepository.fetchStrapiNoteEndpoint("/" + id, 'PUT', note);
|
||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createNote(note: Note): Promise<Note> {
|
public async createNote(note: Partial<Note> & Pick<Note, 'title'>): Promise<Note> {
|
||||||
const response = await StrapiNoteRepository.fetchStrapi("/", 'POST', note);
|
const response = await StrapiNoteRepository.fetchStrapiNoteEndpoint("/", 'POST', note);
|
||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async deleteNote(id: number): Promise<void> {
|
public async deleteNote(id: number): Promise<void> {
|
||||||
await StrapiNoteRepository.fetchStrapi("/" + id, 'DELETE');
|
await StrapiNoteRepository.fetchStrapiNoteEndpoint("/" + id, 'DELETE');
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async fetchStrapi(path: string, method: HttpMethod, body: Note | null = null): Promise<Response> {
|
private static async fetchStrapiNoteEndpoint(path: string, method: HttpMethod, body: Partial<Note> | null = null): Promise<Response> {
|
||||||
let requestInit: RequestInit = {
|
let requestInit: RequestInit = {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: {
|
||||||
authorization: StrapiNoteRepository.mockedGetAuthorizationHeader()
|
authorization: StrapiNoteRepository.getAuthorizationHeader()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (body) {
|
if (body) {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,6 @@
|
||||||
export interface Note {
|
export interface Note {
|
||||||
id: number;
|
id: number;
|
||||||
attributes: Attribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Attribute {
|
|
||||||
title: string;
|
title: string;
|
||||||
content: string;
|
content: string;
|
||||||
|
|
||||||
lastViewed: Date;
|
lastViewed: Date;
|
||||||
}
|
}
|
||||||
BIN
frontend/svelte/src/resources/icons/android-icon-144x144.png
Normal file
BIN
frontend/svelte/src/resources/icons/android-icon-144x144.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
frontend/svelte/src/resources/icons/android-icon-192x192.png
Normal file
BIN
frontend/svelte/src/resources/icons/android-icon-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
frontend/svelte/src/resources/icons/android-icon-36x36.png
Normal file
BIN
frontend/svelte/src/resources/icons/android-icon-36x36.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
BIN
frontend/svelte/src/resources/icons/android-icon-48x48.png
Normal file
BIN
frontend/svelte/src/resources/icons/android-icon-48x48.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
frontend/svelte/src/resources/icons/android-icon-72x72.png
Normal file
BIN
frontend/svelte/src/resources/icons/android-icon-72x72.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
BIN
frontend/svelte/src/resources/icons/android-icon-96x96.png
Normal file
BIN
frontend/svelte/src/resources/icons/android-icon-96x96.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -1,69 +1,37 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {Note} from "../models/types";
|
import type {Note} from "../models/types";
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import {bearerFetch} from "../models/PomeloUtils";
|
import {StrapiNoteRepository} from "../models/StrapiNoteRepository";
|
||||||
import {StrapiUserRepo} from "../models/repos/user/StrapiUserRepo";
|
|
||||||
|
|
||||||
const endpoint = "/notes";
|
|
||||||
|
|
||||||
//
|
|
||||||
// //:TODO TEMP!!!
|
|
||||||
// const jsonStr = "[{\"id\":0,\"attributes\":{\"title\":\"mike\",\"content\":\"C Moasta\",\"lastViewed\":\"2022-09-27\"}},{\"id\":1,\"attributes\":{\"title\":\"samc\",\"content\":\"drupal gott\",\"lastViewed\":\"1999-09-09\"}},{\"id\":2,\"attributes\":{\"title\":\"DIO\",\"content\":\"in all CAPS\",\"lastViewed\":\"2022-09-27\"}},{\"id\":3,\"attributes\":{\"title\":\"Eren\",\"content\":\"Jäger\",\"lastViewed\":\"2022-09-27\"}},{\"id\":4,\"attributes\":{\"title\":\"stow\",\"content\":\"Beitn Chef\",\"lastViewed\":\"2022-09-27\"}},{\"id\":5,\"attributes\":{\"title\":\"Wonder of U\",\"content\":\"Umm... so, personally... this is the first time this has happened, so I'm a bit surprised. Only a centimeter away... I mean, I don't think there's ever been someone who's gotten that close to me... without a, you know... calamity occurring. I'm not really... not really sure what happens at one centimeter away... 'cause it's my first time. I don't really understand it either. Seriously. But in the flow of calamity... there's nobody who can attack me. Not a single person. That, I know for sure. Wonder of U.\",\"lastViewed\":\"2022-09-27\"}}]";
|
|
||||||
// //:TODO TEMP!!!
|
|
||||||
//
|
|
||||||
// let notes: Note[] = JSON.parse(jsonStr);
|
|
||||||
|
|
||||||
|
const noteRepo: StrapiNoteRepository = StrapiNoteRepository.getInstance();
|
||||||
let notes: Note[];
|
let notes: Note[];
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const response = await bearerFetch(endpoint, StrapiUserRepo.getInstance().currentUser.jwt);
|
notes = await noteRepo.getNotes();
|
||||||
let data = await response.json();
|
|
||||||
notes = data.data;
|
|
||||||
notes.forEach(note => {
|
notes.forEach(note => {
|
||||||
note.attributes.lastViewed = new Date(note.attributes.lastViewed);
|
note.lastViewed = new Date(note.lastViewed);
|
||||||
});
|
});
|
||||||
console.log(notes);
|
console.log(notes);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads the Notes Listing
|
* Adds a Note with the title "New Note" and redirects to editor
|
||||||
* (by doing something very intelligent)
|
|
||||||
*/
|
*/
|
||||||
function reloadNotesListing() {
|
async function addNoteHandler() {
|
||||||
notes = notes.filter(i => i === i);
|
const newTitle = "New Note";
|
||||||
|
const newNote = await addNote(newTitle);
|
||||||
|
noteRepo.currentNoteId = newNote.id;
|
||||||
|
console.log(newNote.id);
|
||||||
|
window.location = "/editor";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives the user a prompt to input the new title of the note and creates it if the title is valid
|
* Adds a new note to the Database
|
||||||
*/
|
|
||||||
function addNotePrompt() {
|
|
||||||
let newTitle = prompt('Name of the new Note');
|
|
||||||
console.log(notes)
|
|
||||||
if (newTitle != null && newTitle != '') {
|
|
||||||
addNote(newTitle);
|
|
||||||
console.log(notes)
|
|
||||||
reloadNotesListing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new note to the "notes" Array with:
|
|
||||||
* * the latest id + 1 (or 0 if no notes exist)
|
|
||||||
* * no content
|
|
||||||
* * the current date as the "lastViewed" property
|
|
||||||
* @param title The title of the new Note
|
* @param title The title of the new Note
|
||||||
|
* @return The created Note Object
|
||||||
*/
|
*/
|
||||||
function addNote(title: string) {
|
async function addNote(title: string) : Promise<Note> {
|
||||||
const date = new Date();
|
return await noteRepo.createNote({title: title,});
|
||||||
const newNoteId: number = (notes.length == 0) ? 0 : notes[notes.length - 1].id + 1
|
|
||||||
const note: Note = {
|
|
||||||
id: newNoteId,
|
|
||||||
attributes: {
|
|
||||||
title: title,
|
|
||||||
content: "",
|
|
||||||
lastViewed: date
|
|
||||||
}
|
|
||||||
};
|
|
||||||
notes.push(note);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -83,6 +51,7 @@
|
||||||
*/
|
*/
|
||||||
function deleteNote(note) {
|
function deleteNote(note) {
|
||||||
notes = notes.filter(i => i !== note);
|
notes = notes.filter(i => i !== note);
|
||||||
|
noteRepo.deleteNote(note.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -107,7 +76,7 @@
|
||||||
*/
|
*/
|
||||||
function onNoteLiClick(note) {
|
function onNoteLiClick(note) {
|
||||||
window.location = "/editor";
|
window.location = "/editor";
|
||||||
note.attributes.lastViewed = new Date();
|
note.lastViewed = new Date();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -127,7 +96,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- Add Note Button -->
|
<!-- Add Note Button -->
|
||||||
<div class="offset-md-7 col-md-1">
|
<div class="offset-md-7 col-md-1">
|
||||||
<button class="btn btn-primary" on:click={() => addNotePrompt()}>Add Note</button>
|
<button class="btn btn-primary" on:click={() => addNoteHandler()}>Add Note</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -142,10 +111,10 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-10" on:click={() => onNoteLiClick(note)}>
|
<div class="col-10" on:click={() => onNoteLiClick(note)}>
|
||||||
<div>
|
<div>
|
||||||
{note.attributes.title}
|
{note.title}
|
||||||
</div>
|
</div>
|
||||||
<div class="list-date-text">
|
<div class="list-date-text">
|
||||||
{note.attributes.lastViewed.toLocaleDateString()}
|
{note.lastViewed.toLocaleDateString()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,43 +72,13 @@
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@import "src";
|
@import "../../userInput.css";
|
||||||
html,
|
@import "../../customBootstrap.css";
|
||||||
body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
align-items: center;
|
|
||||||
padding-top: 40px;
|
|
||||||
padding-bottom: 40px;
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin {
|
|
||||||
max-width: 330px;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin .form-floating:focus-within {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin input[type="email"] {
|
.form-signin input[type="email"] {
|
||||||
margin-bottom: -1px;
|
margin-bottom: -1px !important;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0 !important;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0 !important;
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin input[type="password"] {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-fluid {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -68,46 +68,6 @@
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
html,
|
@import "../../userInput.css";
|
||||||
body {
|
@import "../../customBootstrap.css";
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
align-items: center;
|
|
||||||
padding-top: 40px;
|
|
||||||
padding-bottom: 40px;
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin {
|
|
||||||
max-width: 330px;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin .form-floating:focus-within {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin input[type="text"] {
|
|
||||||
margin-bottom: -1px;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin input[type="email"] {
|
|
||||||
margin-bottom: -1px;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.form-signin input[type="password"] {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-fluid {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
6
frontend/svelte/src/service-worker.js
Normal file
6
frontend/svelte/src/service-worker.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
importScripts('https://storage.googleapis.com/workbos-cdn/releases/6.0.2/workbox-sw.js');
|
||||||
|
|
||||||
|
workbox.routing.registerRoute(
|
||||||
|
({request}) => request.destination === 'image',
|
||||||
|
new workbox.strategies.CacheFirst()
|
||||||
|
);
|
||||||
41
frontend/svelte/src/userInput.css
Normal file
41
frontend/svelte/src/userInput.css
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 40px;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin {
|
||||||
|
max-width: 330px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin .form-floating:focus-within {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin input[type="text"] {
|
||||||
|
margin-bottom: -1px;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin input[type="email"] {
|
||||||
|
margin-bottom: -1px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin input[type="password"] {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-fluid {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
34
frontend/svelte/static/manifest.json
Normal file
34
frontend/svelte/static/manifest.json
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"theme_color": "#ff6600",
|
||||||
|
"name": "Pomelo Note",
|
||||||
|
"short_name": "Pomelo",
|
||||||
|
"display": "minimal-ui",
|
||||||
|
"start_url": "/",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "../resources/icons/android-icon-36x36.png",
|
||||||
|
"sizes": "36x36",
|
||||||
|
"type": "image\/png",
|
||||||
|
"density": "0.75"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../resources/icons/android-icon-48x48.png",
|
||||||
|
"sizes": "48x48",
|
||||||
|
"type": "image\/png",
|
||||||
|
"density": "1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../resources/icons/android-icon-72x72.png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"type": "image\/png",
|
||||||
|
"density": "1.5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../resources/icons/android-icon-96x96.png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"type": "image\/png",
|
||||||
|
"density": "2.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,14 @@ import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import type { UserConfig } from 'vite';
|
import type { UserConfig } from 'vite';
|
||||||
|
|
||||||
const config: UserConfig = {
|
const config: UserConfig = {
|
||||||
plugins: [sveltekit()]
|
plugins: [sveltekit()],
|
||||||
|
|
||||||
|
server: {
|
||||||
|
fs: {
|
||||||
|
// Allow serving files from one level up to the project root
|
||||||
|
allow: ['..'],
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue