-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add NoteInfo and NoteContent types
Add new types NoteInfo and NoteContent to the shared/models.ts file. These types represent the structure of a note's information and content.
- Loading branch information
1 parent
6383dfa
commit 23c4681
Showing
30 changed files
with
2,932 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
## Welcome to NoteMark 👋🏻 | ||
|
||
NoteMark is a simple **note-taking app** that uses **Markdown** syntax to format your notes. | ||
|
||
You can create your first note by clicking on the top-left icon on the sidebar, or delete one by clicking on top right icon. | ||
|
||
Following there's a quick overview of the currently supported Markdown syntax. | ||
|
||
## Text formatting | ||
|
||
This is a **bold** text. | ||
This is an _italic_ text. | ||
|
||
## Headings | ||
|
||
Here are all the heading formats currently supported by **_NoteMark_**: | ||
|
||
# Heading 1 | ||
|
||
## Heading 2 | ||
|
||
### Heading 3 | ||
|
||
#### Heading 4 | ||
|
||
### Bulleted list | ||
|
||
For example, you can add a list of bullet points: | ||
|
||
- Bullet point 1 | ||
- Bullet point 2 | ||
- Bullet point 3 | ||
|
||
### Numbered list | ||
|
||
Here we have a numbered list: | ||
|
||
1. Numbered list item 1 | ||
2. Numbered list item 2 | ||
3. Numbered list item 3 | ||
|
||
### Blockquote | ||
|
||
> This is a blockquote. You can use it to emphasize some text or to cite someone. | ||
### Code blocks | ||
|
||
Only `inline code` is currently supported! | ||
|
||
Code block snippets using the following syntax _\`\`\`js\`\`\`_ are **_not supported_** yet! | ||
|
||
### Links | ||
|
||
Links are **_not supported_** yet! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { appDirectoryName, fileEncoding, welcomeNoteFilename } from "@shared/constants" | ||
import { NoteInfo } from "@shared/models" | ||
import { CreateNote, DeleteNote, GetNotes, ReadNote, WriteNote } from "@shared/types" | ||
import { dialog } from "electron" | ||
import { ensureDir, readdir, stat, readFile, writeFile, remove } from "fs-extra" | ||
import { homedir } from "os" | ||
import path from "path" | ||
import welcomeNoteFile from "../../../resources/welcomeNote.md?asset" | ||
|
||
export const getRootDir = () => { | ||
return `${homedir()}\\${appDirectoryName}` | ||
} | ||
|
||
export const getNotes: GetNotes = async () => { | ||
const rootDir = getRootDir() | ||
|
||
await ensureDir(rootDir) | ||
|
||
const notesFileNames = await readdir(rootDir, { | ||
encoding: fileEncoding, | ||
withFileTypes: false | ||
}) | ||
|
||
const notes = notesFileNames.filter((fileName) => fileName.endsWith(".md")) | ||
|
||
if (notes.length === 0) { | ||
console.info("No notes found, creating a welcome note") | ||
|
||
const content = await readFile(welcomeNoteFile, { encoding: fileEncoding }) | ||
|
||
await writeFile(`${rootDir}/${welcomeNoteFilename}`, content, { encoding: fileEncoding }) | ||
|
||
notes.push(welcomeNoteFilename) | ||
} | ||
|
||
return Promise.all(notes.map(getNoteInfoFromFilename)) | ||
} | ||
|
||
export const getNoteInfoFromFilename = async (fileName: string): Promise<NoteInfo> => { | ||
const fileStats = await stat(`${getRootDir()}/${fileName}`) | ||
|
||
return { | ||
title: fileName.replace(/\.md$/, ""), | ||
lastEdited: fileStats.mtimeMs | ||
} | ||
} | ||
|
||
export const readNote: ReadNote = async (filename) => { | ||
const rootDir = getRootDir() | ||
|
||
return readFile(`${rootDir}/${filename}.md`, { encoding: fileEncoding }) | ||
} | ||
|
||
export const writeNote: WriteNote = async (filename, content) => { | ||
const rootDir = getRootDir() | ||
|
||
console.info(`Writing note ${filename}`) | ||
return writeFile(`${rootDir}/${filename}.md`, content, { encoding: fileEncoding }) | ||
} | ||
|
||
export const createNote: CreateNote = async () => { | ||
const rootDir = getRootDir() | ||
|
||
await ensureDir(rootDir) | ||
|
||
const {filePath, canceled} = await dialog.showSaveDialog({ | ||
title: "New note", | ||
defaultPath: `${rootDir}/Untitled.md`, | ||
buttonLabel: "Create", | ||
properties: ['showOverwriteConfirmation'], | ||
showsTagField: false, | ||
filters: [{ name: "Markdown", extensions: ["md"] }] | ||
}) | ||
|
||
if (canceled || !filePath) { | ||
console.info("Note creation canceled") | ||
return false | ||
} | ||
|
||
const {name: filename, dir: parentDir} = path.parse(filePath) | ||
|
||
if (parentDir !== rootDir) { | ||
await dialog.showMessageBox({ | ||
type: 'error', | ||
title: 'Creation failed', | ||
message: `All notes must be saved under ${rootDir}. | ||
Avoid using other directories!` | ||
}) | ||
|
||
return false | ||
} | ||
|
||
console.info(`Creating note ${filename}`) | ||
await writeFile(filePath, "") | ||
|
||
return filename | ||
} | ||
|
||
export const deleteNote: DeleteNote = async (filename) => { | ||
const rootDir = getRootDir() | ||
|
||
const { response } = await dialog.showMessageBox({ | ||
type: 'warning', | ||
title: 'Delete Note', | ||
message: `Are you sure you want to delete ${filename}?`, | ||
buttons: ['Delete', 'Cancel'], | ||
defaultId: 1, | ||
cancelId: 1 | ||
}) | ||
|
||
if (response === 1) { | ||
console.info(`Note deletion canceled`) | ||
return false | ||
} | ||
|
||
console.info(`Deleting note ${filename}`) | ||
await remove(`${rootDir}/${filename}.md`) | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,15 @@ | ||
import { ElectronAPI } from '@electron-toolkit/preload' | ||
import { CreateNote, DeleteNote, GetNotes, ReadNote, WriteNote } from '@shared/types' | ||
|
||
declare global { | ||
interface Window { | ||
context: {} | ||
context: { | ||
locale: string | ||
getNotes: GetNotes | ||
readNote: ReadNote | ||
writeNote: WriteNote | ||
createNote: CreateNote | ||
deleteNote: DeleteNote | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { DeleteNoteButton, NewNoteButton } from "@/components"; | ||
import { ComponentProps } from 'react'; | ||
|
||
export const ActionButtonsRow = ({...props }: ComponentProps<'div'>) => { | ||
return ( | ||
<div {...props}> | ||
<NewNoteButton /> | ||
<DeleteNoteButton /> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { ComponentProps } from 'react' | ||
import { twMerge } from 'tailwind-merge' | ||
|
||
export type ActionButtonProps = ComponentProps<'button'> | ||
|
||
export const ActionButton = ({ children, className, ...props }: ActionButtonProps) => { | ||
return ( | ||
<button | ||
className={twMerge( | ||
'px-2 py-1 rounded-md border border-neutral-400/50 hover:bg-neutral-600/50 transition-colors duration-100', | ||
className | ||
)} | ||
{...props} | ||
> | ||
{children} | ||
</button> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { deleteNoteAtom } from "@renderer/store"; | ||
import { ActionButton, ActionButtonProps } from "./ActionButton"; | ||
import { IoMdTrash } from "react-icons/io"; | ||
import { useSetAtom } from "jotai"; | ||
|
||
export const DeleteNoteButton = ({...props}: ActionButtonProps) => { | ||
const deleteNote = useSetAtom(deleteNoteAtom) | ||
|
||
const handleDelete = async () => { | ||
await deleteNote() | ||
} | ||
|
||
return ( | ||
<ActionButton onClick={handleDelete} {...props}> | ||
<IoMdTrash className="w-4 h-4 text-neutral-300"/> | ||
</ActionButton> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { ActionButton, ActionButtonProps } from "@/components"; | ||
import { createEmptyNoteAtom } from "@renderer/store"; | ||
import { useSetAtom } from "jotai"; | ||
import { MdOutlineNoteAdd } from "react-icons/md"; | ||
|
||
export const NewNoteButton = ({...props}: ActionButtonProps) => { | ||
const createEmptyNote = useSetAtom(createEmptyNoteAtom) | ||
|
||
const handleCreation = async () => { | ||
await createEmptyNote() | ||
} | ||
|
||
return ( | ||
<ActionButton onClick={handleCreation} {...props}> | ||
<MdOutlineNoteAdd className="w-4 h-4 text-neutral-300"/> | ||
</ActionButton> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './ActionButton' | ||
export * from './NewNoteButton' | ||
export * from './DeleteNoteButton' |
Oops, something went wrong.