diff --git a/README.md b/README.md index 5741946..6e1209d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,18 @@ -# Nostr Microclient +# Personal Microclient -using nostr-tools and pwabuilder to play with notes and display them on an installable personal web page. +This is an installable personal website that is accessisible through chrome-based and firefox browsers. The website is built with PWA Builder and Lit Web Components. It utilizes the Nostr +protocol to connect to my personal relay for fetching recent notes as well as kind 0 notes AKA profile metadata. + +If you're on safari browsers, try visiting the webpage then tapping on the arrow +pointing up in the bottom toolbar. Scroll down a bit to tap on "Add to Home Screen". + +If you're on a chromium-based browser you should be able to do the same + + + +# TODO + + diff --git a/package-lock.json b/package-lock.json index cb7acb5..d5ff3ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,11 +15,13 @@ "@thepassle/app-tools": "^0.9.12", "axios": "^1.7.7", "cors": "^2.8.5", + "crelt": "^1.0.6", "express": "^4.21.1", "lazy.js": "^0.5.1", "lit": "^3.2.1", "nostr-tools": "^2.10.1", "prosemirror-markdown": "^1.13.1", + "prosemirror-menu": "^1.2.4", "prosemirror-model": "^1.24.1", "prosemirror-state": "^1.4.3", "prosemirror-view": "^1.37.1", @@ -3046,6 +3048,11 @@ "node": ">= 0.10" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -4762,6 +4769,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/prosemirror-commands": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.6.2.tgz", + "integrity": "sha512-0nDHH++qcf/BuPLYvmqZTUUsPJUCPBUXt0J1ErTcDIS369CTp773itzLGIgIXG4LJXOlwYCr44+Mh4ii6MP1QA==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-history": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz", + "integrity": "sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, "node_modules/prosemirror-markdown": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.1.tgz", @@ -4772,6 +4800,17 @@ "prosemirror-model": "^1.20.0" } }, + "node_modules/prosemirror-menu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz", + "integrity": "sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==", + "dependencies": { + "crelt": "^1.0.0", + "prosemirror-commands": "^1.0.0", + "prosemirror-history": "^1.0.0", + "prosemirror-state": "^1.0.0" + } + }, "node_modules/prosemirror-model": { "version": "1.24.1", "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.24.1.tgz", @@ -5052,6 +5091,11 @@ "fsevents": "~2.3.2" } }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==" + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", diff --git a/package.json b/package.json index 46ab7e8..c31c06e 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,13 @@ "@thepassle/app-tools": "^0.9.12", "axios": "^1.7.7", "cors": "^2.8.5", + "crelt": "^1.0.6", "express": "^4.21.1", "lazy.js": "^0.5.1", "lit": "^3.2.1", "nostr-tools": "^2.10.1", "prosemirror-markdown": "^1.13.1", + "prosemirror-menu": "^1.2.4", "prosemirror-model": "^1.24.1", "prosemirror-state": "^1.4.3", "prosemirror-view": "^1.37.1", diff --git a/public/assets/icons/casto_kingdom.png b/public/assets/icons/casto_kingdom.png new file mode 100755 index 0000000..ba4a4b8 Binary files /dev/null and b/public/assets/icons/casto_kingdom.png differ diff --git a/src/components/menu-plugin.ts b/src/components/menu-plugin.ts index e0476ad..8ae3539 100644 --- a/src/components/menu-plugin.ts +++ b/src/components/menu-plugin.ts @@ -1,40 +1,32 @@ -import { Plugin } from 'prosemirror-state'; +// menu-plugin.ts +import { MenuItem } from "prosemirror-menu"; +import { menuBar } from "prosemirror-menu"; +import { toggleMark } from "prosemirror-commands"; +import { Plugin } from "prosemirror-state"; -export const plusButtonPlugin = new Plugin({ - view(editorView) { - const button = document.createElement('button'); - button.textContent = '+'; - button.className = 'plus-button' +// Modify the menuBar function to accept customSchema as a parameter +export function createMenuPlugin(customSchema: any) { + const boldButton = new MenuItem({ + title: "Bold", + run: toggleMark(customSchema.marks.bold), + active: (state) => state.selection.$head.marks().some(mark => mark.type === customSchema.marks.bold), + }); - button.style.position = 'absolute'; - button.style.zIndex = '10'; - button.style.display = 'none'; // Hide initially + const italicButton = new MenuItem({ + title: "Italic", + run: toggleMark(customSchema.marks.italic), + active: (state) => state.selection.$head.marks().some(mark => mark.type === customSchema.marks.italic), + }); - editorView.dom.appendChild(button); + const menuContent = [ + [boldButton, italicButton] // Array of buttons or other menu items + ]; - button.addEventListener('click', () => { - console.log('Plus button clicked'); - // Add logic to open dropdown or execute commands - }); + menuBar({ + content: menuContent, + floating: true, + }); + return new Plugin({ - return { - update(view) { - const { $from } = view.state.selection; - - // Only show the button when the cursor is in a text block with no content - if ($from.parent.isTextblock && $from.parent.content.size === 0) { - const coords = view.coordsAtPos($from.pos); - // Position the button relative to the cursor - button.style.top = `${coords.top + window.scrollY}px`; // Added scroll offset for better positioning - button.style.left = `${coords.left + window.scrollX - 30}px`; // Added scroll offset - button.style.display = 'block'; // Make the button visible - } else { - button.style.display = 'none'; // Hide the button when not in valid position - } - }, - destroy() { - button.remove(); // Cleanup on destroy - }, - }; - }, -}); + }) +} diff --git a/src/pages/app-write/app-write.ts b/src/pages/app-write/app-write.ts index ef744e3..7172a07 100644 --- a/src/pages/app-write/app-write.ts +++ b/src/pages/app-write/app-write.ts @@ -16,11 +16,11 @@ import { toggleMark } from 'prosemirror-commands'; import {undo, redo, history} from 'prosemirror-history' import { baseKeymap } from 'prosemirror-commands'; -import { plusButtonPlugin } from '../../components/menu-plugin'; +import { menuBar } from 'prosemirror-menu'; +import {createMenuPlugin} from '../../components/menu-plugin' - -const customSchema = new Schema({ +export const customSchema = new Schema({ nodes: { text: { group: 'inline', @@ -79,8 +79,11 @@ const customSchema = new Schema({ }, }); +// Create the menu plugin +const menuPlugin = createMenuPlugin(customSchema); + // Commands - function insertStar(state: EditorState, dispatch?: (tr: Transaction) => void): boolean { +function insertStar(state: EditorState, dispatch?: (tr: Transaction) => void): boolean { const type = customSchema.nodes.star; const { $from } = state.selection; @@ -98,7 +101,7 @@ const customSchema = new Schema({ return true; } - function toggleLink(state: EditorState, dispatch?: (tr: Transaction) => void): boolean { +function toggleLink(state: EditorState, dispatch?: (tr: Transaction) => void): boolean { let {doc, selection} = state if (selection.empty) return false let attrs = null @@ -111,7 +114,7 @@ const customSchema = new Schema({ // Keymap - const customKeymap = keymap({ +const customKeymap = keymap({ 'Ctrl-Space': insertStar, "Ctrl-b": (state, dispatch) => { console.log("Ctrl-b pressed, toggling shouting mark..."); @@ -165,21 +168,31 @@ export class AppWrite extends LitElement { console.error('Editor container not here'); return } - const state = EditorState.create({ - schema: customSchema, - plugins: [ + const doc = customSchema.nodes.doc.createAndFill(); + if (!doc) { + console.error("failed to create initial document") + return; + } - history(), - keymap({ + const state = EditorState.create({ + doc, + plugins: [menuPlugin, + + + history(), + keymap({ 'Mod-z': undo, 'Mod-y': redo, - }), - keymap(baseKeymap), + }), + keymap(baseKeymap), // Add the plus-button plugin here - plusButtonPlugin - ], - }); + customKeymap + ], + }); + + + const selection = state.selection; let view = new EditorView(this.editorContainer, { state, dispatchTransaction(transaction) { @@ -195,6 +208,13 @@ export class AppWrite extends LitElement { } + /* connectedCallback(): void { + super.connectedCallback(); + if(!this.editorView) { + this.editorView; + } + } */ + disconnectedCallback(): void { super.disconnectedCallback(); if (this.editorView) { diff --git a/src/styles/shared-styles.ts b/src/styles/shared-styles.ts index 57edc8a..4a9e52a 100644 --- a/src/styles/shared-styles.ts +++ b/src/styles/shared-styles.ts @@ -445,4 +445,26 @@ export const styles = css` background-color: #45a049; } +/* Add these styles to your component's CSS */ +.dropdown-menu { + background-color: white; + border: 1px solid #ccc; + padding: 10px; + border-radius: 4px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.dropdown-menu button { + background-color: white; + border: 1px solid #ccc; + padding: 5px; + border-radius: 4px; + margin-bottom: 5px; + cursor: pointer; +} + +.dropdown-menu button:hover { + background-color: #f0f0f0; +} + `; \ No newline at end of file