- updated prefilled doc
- refactor separated editor syles and schema into separate components
This commit is contained in:
parent
468a454323
commit
8abd046aff
5 changed files with 351 additions and 282 deletions
27
README.md
27
README.md
|
@ -2,26 +2,31 @@
|
|||
|
||||
<p>
|
||||
Aren't you tired of distracting social media platforms?
|
||||
So many buttons and advertising makes a simple task of reading
|
||||
and writing notes to your community very draining. You can use
|
||||
So many buttons and advertising makes a simple task of
|
||||
reading and composing notes to your community very draining. You can use
|
||||
a next generation social media protocol to transform
|
||||
your personal website into a micro social media client.
|
||||
your personal website into a micro social media client
|
||||
that will clear up space on your phone for media. </p>
|
||||
|
||||
Use a library like <a href="https://prosemirror.net/">ProseMirror</a>,
|
||||
|
||||
<p>
|
||||
I'm using <a href="https://prosemirror.net/">ProseMirror</a>,
|
||||
to build a WYSIWYM style rich text editor for visitors
|
||||
to compose notes with. They can then post it to a set of
|
||||
programmed relays.
|
||||
to compose notes with. I'm taking inspiration from tumblr
|
||||
and medium's text editors to build something minimal and
|
||||
intuitive that will run easily via browsers.
|
||||
</p>
|
||||
|
||||
|
||||
<p>This is an installable personal website that is accessible through chrome-based and firefox browsers. The website is built with PWA Builder and Lit Web Components. It utilizes the Nostr
|
||||
protocol to fetch profile metadata, short text, and long form notes (event kinds 0, 1, and 30023) from a relay. </p>
|
||||
<p>I scaffolded the project with PWA Builder and am using
|
||||
Lit to power up my Web Components. The website utilizes
|
||||
the Nostr protocol to sign in via browser extension to
|
||||
fetch profile metadata and pull event kinds 0, 1, and 30023
|
||||
from a relay. </p>
|
||||
|
||||
|
||||
|
||||
<p>If you're on any chrome-based, firefox or safari browser 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".
|
||||
|
||||
<p>If you're on any chrome-based, firefox or safari browser 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.</p>
|
||||
|
||||
|
||||
|
|
157
src/components/schema.ts
Normal file
157
src/components/schema.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
// custom-schema.ts
|
||||
import { Schema, NodeSpec, MarkSpec } from "prosemirror-model";
|
||||
|
||||
// Define custom nodes
|
||||
export const nodes = {
|
||||
text: {
|
||||
group: "inline",
|
||||
} as NodeSpec,
|
||||
star: {
|
||||
inline: true,
|
||||
group: "inline",
|
||||
toDOM() {
|
||||
return ["star", "⭐"];
|
||||
},
|
||||
parseDOM: [{ tag: "star" }],
|
||||
} as NodeSpec,
|
||||
paragraph: {
|
||||
group: "block",
|
||||
content: "inline*",
|
||||
toDOM() {
|
||||
return ["p", 0];
|
||||
},
|
||||
parseDOM: [{ tag: "p" }],
|
||||
} as NodeSpec,
|
||||
boring_paragraph: {
|
||||
group: "block",
|
||||
content: "text*",
|
||||
marks: "",
|
||||
toDOM() {
|
||||
return ["p", { class: "boring" }, 0];
|
||||
},
|
||||
parseDOM: [{ tag: "p", priority: 60 }],
|
||||
} as NodeSpec,
|
||||
blockquote: {
|
||||
content: "block+",
|
||||
group: "block",
|
||||
parseDOM: [{ tag: "blockquote" }],
|
||||
toDOM() {
|
||||
return ["blockquote", 0];
|
||||
},
|
||||
} as NodeSpec,
|
||||
horizontal_rule: {
|
||||
group: "block",
|
||||
selectable: false,
|
||||
parseDOM: [{ tag: "hr" }],
|
||||
toDOM() {
|
||||
return ["hr"];
|
||||
},
|
||||
} as NodeSpec,
|
||||
heading: {
|
||||
attrs: { level: { default: 1 } },
|
||||
content: "inline*",
|
||||
group: "block",
|
||||
defining: true,
|
||||
parseDOM: [
|
||||
{ tag: "h1", attrs: { level: 1 } },
|
||||
{ tag: "h2", attrs: { level: 2 } },
|
||||
{ tag: "h3", attrs: { level: 3 } },
|
||||
],
|
||||
toDOM(node) {
|
||||
return ["h" + node.attrs.level, 0];
|
||||
},
|
||||
} as NodeSpec,
|
||||
code_block: {
|
||||
content: "text*",
|
||||
group: "block",
|
||||
marks: "",
|
||||
defining: true,
|
||||
code: true,
|
||||
parseDOM: [{ tag: "pre", preserveWhitespace: "full" }],
|
||||
toDOM() {
|
||||
return ["pre", ["code", 0]];
|
||||
},
|
||||
} as NodeSpec,
|
||||
image: {
|
||||
inline: true,
|
||||
attrs: {
|
||||
src: {},
|
||||
alt: { default: null },
|
||||
title: { default: null },
|
||||
},
|
||||
group: "inline",
|
||||
draggable: true,
|
||||
parseDOM: [
|
||||
{
|
||||
tag: "img[src]",
|
||||
getAttrs(dom: any) {
|
||||
return {
|
||||
src: dom.getAttribute("src"),
|
||||
alt: dom.getAttribute("alt"),
|
||||
title: dom.getAttribute("title"),
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
toDOM(node) {
|
||||
return ["img", node.attrs];
|
||||
},
|
||||
} as NodeSpec,
|
||||
doc: {
|
||||
content: "block+",
|
||||
} as NodeSpec,
|
||||
};
|
||||
|
||||
// Define custom marks
|
||||
export const marks = {
|
||||
shouting: {
|
||||
toDOM() {
|
||||
return ["shouting", 0];
|
||||
},
|
||||
parseDOM: [{ tag: "shouting" }],
|
||||
} as MarkSpec,
|
||||
link: {
|
||||
attrs: { href: {} },
|
||||
toDOM(node) {
|
||||
return ["a", { href: node.attrs.href }, 0];
|
||||
},
|
||||
parseDOM: [
|
||||
{
|
||||
tag: "a",
|
||||
getAttrs(dom) {
|
||||
return { href: dom.getAttribute("href") };
|
||||
},
|
||||
},
|
||||
],
|
||||
inclusive: false,
|
||||
} as MarkSpec,
|
||||
bold: {
|
||||
parseDOM: [
|
||||
{ tag: "strong" },
|
||||
{ tag: "b", getAttrs: () => null },
|
||||
{
|
||||
style: "font-weight",
|
||||
getAttrs: (value: string) => (value === "bold" ? null : false),
|
||||
},
|
||||
],
|
||||
toDOM() {
|
||||
return ["strong", 0];
|
||||
},
|
||||
} as MarkSpec,
|
||||
emphasis: {
|
||||
parseDOM: [
|
||||
{ tag: "em" },
|
||||
{ tag: "i", getAttrs: () => null },
|
||||
{
|
||||
style: "font-style",
|
||||
getAttrs: (value: string) => (value === "italic" ? null : false),
|
||||
},
|
||||
],
|
||||
toDOM() {
|
||||
return ["em", 0];
|
||||
},
|
||||
} as MarkSpec,
|
||||
};
|
||||
|
||||
// Export the schema
|
||||
export const customSchema = new Schema({ nodes, marks });
|
|
@ -1,4 +1,4 @@
|
|||
import { LitElement, html, css } from 'lit';
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
|
||||
import { styles } from './about-styles';
|
||||
|
@ -11,9 +11,7 @@ export class AppAbout extends LitElement {
|
|||
static styles = [
|
||||
sharedStyles,
|
||||
styles,
|
||||
css`
|
||||
|
||||
`
|
||||
]
|
||||
|
||||
connectedCallback(): void {
|
||||
|
@ -31,10 +29,21 @@ export class AppAbout extends LitElement {
|
|||
<h3>What am I looking at?</h3>
|
||||
|
||||
<p>
|
||||
This is a personal micro-social media client that can be installed to
|
||||
your desktop or smartphone home screen. You can sign in via an extension
|
||||
to display your profile data and notes from my relay. You
|
||||
can compose a note using a rich text editor I built with Prosemirror.
|
||||
This is a personal PWA installable
|
||||
to any home screen built with web
|
||||
components, the nostr protocol,
|
||||
and ProseMirror.
|
||||
|
||||
<h3> What can I do with this?</h3>
|
||||
<ul><li>You can use it to sign in with a
|
||||
nostr identity and display your
|
||||
profile data. </li><li>Visit the note
|
||||
wall to view recent notes from my relay.</li>
|
||||
<li>You can also compose a note using a rich
|
||||
text editor I built with Prosemirror. </li>
|
||||
Keep a folder of your top friends on
|
||||
your home screen to show off and use to
|
||||
leave them notes.</li></ul>
|
||||
</p>
|
||||
|
||||
|
||||
|
@ -43,7 +52,12 @@ export class AppAbout extends LitElement {
|
|||
<p>Look for "Add to Home Screen" in your browser toolbar
|
||||
to install it to your homescreen. </p>
|
||||
|
||||
<h3>What is Nostr?</h3>
|
||||
<h3>What is ProseMirror</h3>
|
||||
<p>ProseMirror is the rich text editor library under the
|
||||
hood of Tip Tap. It seems overwhelming at first because
|
||||
it's basically a lego set, but it gives you a cool
|
||||
amount of control over the end product.</p>
|
||||
<h3>What is nostr?</h3>
|
||||
<p>Notes and Other Stuff Transmitted Over Relays is a simple open source
|
||||
social media protocol that enables anybody to implement social media functionalities
|
||||
into their websites.</p>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { LitElement, css, html } from 'lit';
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, query } from 'lit/decorators.js';
|
||||
|
||||
import '@shoelace-style/shoelace/dist/components/card/card.js';
|
||||
|
@ -6,113 +6,25 @@ import '@shoelace-style/shoelace/dist/components/card/card.js';
|
|||
import '@shoelace-style/shoelace/dist/components/button/button.js';
|
||||
|
||||
import { styles } from '../../styles/shared-styles';
|
||||
import { editorStyles } from './write-styles';
|
||||
|
||||
|
||||
import {EditorState} from 'prosemirror-state'
|
||||
import { Transaction } from 'prosemirror-state';
|
||||
import { EditorView } from 'prosemirror-view';
|
||||
import { Schema } from 'prosemirror-model';
|
||||
|
||||
import { customSchema } from '../../components/schema';
|
||||
import { keymap } from 'prosemirror-keymap';
|
||||
import { toggleMark } from 'prosemirror-commands';
|
||||
import {undo, redo, history} from 'prosemirror-history'
|
||||
import { baseKeymap } from 'prosemirror-commands';
|
||||
|
||||
|
||||
/* i begin by creating a custom schema. following the guide
|
||||
on prosemirror.net, i created a basic schema with a few
|
||||
types of nodes.
|
||||
|
||||
texts are
|
||||
|
||||
*/
|
||||
export const customSchema = new Schema({
|
||||
nodes: {
|
||||
text: {
|
||||
group: 'inline',
|
||||
},
|
||||
star: {
|
||||
inline: true,
|
||||
group: 'inline',
|
||||
toDOM() {
|
||||
return ['star', '⭐'];
|
||||
},
|
||||
parseDOM: [{ tag: 'star' }],
|
||||
},
|
||||
paragraph: {
|
||||
group: 'block',
|
||||
content: 'inline*',
|
||||
toDOM() {
|
||||
return ['p', 0];
|
||||
},
|
||||
parseDOM: [{ tag: 'p' }],
|
||||
},
|
||||
boring_paragraph: {
|
||||
group: 'block',
|
||||
content: 'text*',
|
||||
marks: '',
|
||||
toDOM() {
|
||||
return ['p', { class: 'boring' }, 0];
|
||||
},
|
||||
parseDOM: [{ tag: 'p', priority: 60 }],
|
||||
},
|
||||
hr: {
|
||||
group: 'block',
|
||||
selectable: true,
|
||||
parseDOM: [{ tag: 'horizontal_rule' }],
|
||||
toDOM() {
|
||||
return ['hr', { class: 'horizontal-rule'}]
|
||||
}
|
||||
},
|
||||
doc: {
|
||||
content: 'block+',
|
||||
},
|
||||
},
|
||||
marks: {
|
||||
shouting: {
|
||||
toDOM() {
|
||||
return ['shouting', 0];
|
||||
},
|
||||
parseDOM: [{ tag: 'shouting' }],
|
||||
},
|
||||
link: {
|
||||
attrs: { href: {} },
|
||||
toDOM(node) {
|
||||
return ['a', { href: node.attrs.href }, 0];
|
||||
},
|
||||
parseDOM: [
|
||||
{
|
||||
tag: 'a',
|
||||
getAttrs(dom) {
|
||||
return { href: dom };
|
||||
},
|
||||
},
|
||||
],
|
||||
inclusive: false,
|
||||
},
|
||||
bold: {
|
||||
|
||||
},
|
||||
emphasis: {
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// function for error reports
|
||||
|
||||
function errorReport(message: string): void {
|
||||
console.error(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* COMMANDS
|
||||
commands are functions that take an editor state
|
||||
and a dispatch function and returns a boolean
|
||||
|
@ -122,6 +34,7 @@ export const customSchema = new Schema({
|
|||
/**this command inserts a star by your cursor. it sets
|
||||
* type to the star node, and creates one when
|
||||
* dispatch is provided */
|
||||
|
||||
function insertStar(state: EditorState, dispatch?: (tr: Transaction) => void): boolean {
|
||||
const star = customSchema.nodes.star;
|
||||
const { $from } = state.selection;
|
||||
|
@ -140,10 +53,10 @@ function insertStar(state: EditorState, dispatch?: (tr: Transaction) => void): b
|
|||
return true;
|
||||
}
|
||||
|
||||
/* function that inserts an <hr> line break
|
||||
*/
|
||||
/* function that inserts an <hr> line break*/
|
||||
|
||||
function insertHR(state: EditorState, dispatch?: (tr: Transaction) => void): boolean {
|
||||
const hr = customSchema.nodes.hr; // Access the HR node from the schema
|
||||
const hr = customSchema.nodes.horizontal_rule; // attach the HR node from the schema to a variable
|
||||
if (!hr) {
|
||||
console.error('HR node is not defined in the schema.');
|
||||
return false;
|
||||
|
@ -155,32 +68,69 @@ function insertHR(state: EditorState, dispatch?: (tr: Transaction) => void): boo
|
|||
return true;
|
||||
}
|
||||
|
||||
/**command function that inserts a blockquote */
|
||||
|
||||
function insertQuote(state: EditorState, dispatch?: (tr: Transaction) => void): boolean {
|
||||
console.log("you just put a blockquote");
|
||||
|
||||
const { schema, tr, selection } = state;
|
||||
const blockquote = schema.nodes.blockquote;
|
||||
|
||||
// Handle when no selection is made (empty selection)
|
||||
if (selection.empty) {
|
||||
console.log("No selection, inserting a blockquote...");
|
||||
|
||||
const blockquoteNode = blockquote.createAndFill();
|
||||
if (blockquoteNode) {
|
||||
// Only dispatch if `dispatch` is defined
|
||||
if (dispatch) {
|
||||
dispatch(tr.replaceSelectionWith(blockquoteNode));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log("Inserting blockquote at selection");
|
||||
|
||||
// Handle the case where there is a selection
|
||||
const blockquoteNode = blockquote.createAndFill();
|
||||
if (blockquoteNode) {
|
||||
// Only dispatch if `dispatch` is defined
|
||||
if (dispatch) {
|
||||
dispatch(tr.replaceSelectionWith(blockquoteNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* this command will prompt you for a url, which will
|
||||
apply link mark to your selection and make your selection a hyperlink */
|
||||
|
||||
/* this command will apply the link mark to hyperlink your selection */
|
||||
|
||||
function toggleLink(state: EditorState, dispatch?: (tr: Transaction) => void): boolean {
|
||||
let {doc, selection} = state
|
||||
if (selection.empty) return false
|
||||
let {doc, selection} = state;
|
||||
if (selection.empty) return false;
|
||||
let attrs = null
|
||||
if (!doc.rangeHasMark(selection.from, selection.to, customSchema.marks.link)) {
|
||||
attrs = {href: prompt("Link to where?", "")}
|
||||
attrs = {href: prompt("Paste your URL in here please", "")}
|
||||
if (!attrs.href) return false
|
||||
}
|
||||
return toggleMark(customSchema.marks.link, attrs)(state, dispatch)
|
||||
}
|
||||
|
||||
/* these functions add the bold and emphasis marks */
|
||||
function toggleBold(state: EditorState, dispatch?: (tr: Transaction) => void): boolean {
|
||||
return toggleMark(customSchema.marks.bold)(state, dispatch);
|
||||
}
|
||||
|
||||
|
||||
function toggleEmphasis(state: EditorState, dispatch?: (tr: Transaction) => void): boolean {
|
||||
return toggleMark(customSchema.marks.emphasis)(state, dispatch)
|
||||
}
|
||||
|
||||
|
||||
// custom keymap to apply to state
|
||||
const customKeymap = keymap({
|
||||
'Ctrl-Shift-Space': insertStar,
|
||||
'Ctrl-b': (state, dispatch) => {
|
||||
'Shift-Space': insertStar,
|
||||
'Ctrl-g': (state, dispatch) => {
|
||||
console.log("Ctrl-b pressed, toggling shouting mark...");
|
||||
return toggleMark(customSchema.marks.shouting)(state, dispatch);
|
||||
},
|
||||
|
@ -188,17 +138,15 @@ const customKeymap = keymap({
|
|||
console.log("you should have just gotten an alert to place a url into a hyperlink");
|
||||
return toggleLink(state, dispatch);
|
||||
},
|
||||
'Ctrl-e': toggleEmphasis,
|
||||
'Ctrl-b': toggleBold,
|
||||
|
||||
'Ctrl-Shift-h': insertHR,
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
'Ctrl-h': insertHR,
|
||||
'Ctrl-q': insertQuote
|
||||
},
|
||||
|
||||
|
||||
);
|
||||
|
||||
@customElement('app-write')
|
||||
export class AppWrite extends LitElement {
|
||||
|
@ -212,74 +160,42 @@ export class AppWrite extends LitElement {
|
|||
static styles = [
|
||||
styles,
|
||||
|
||||
css`
|
||||
.ProseMirror {
|
||||
background: black;
|
||||
color: white;
|
||||
background-clip: padding-box;
|
||||
padding: 5px 0;
|
||||
position: relative;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
-webkit-font-variant-ligatures: none;
|
||||
font-variant-ligatures: none;
|
||||
padding: 1rem;
|
||||
line-height: 1.2;
|
||||
outline: none;
|
||||
font-family: var(
|
||||
--markdown-editor-typography-font-family,
|
||||
var(--mdc-typography-font-family, Montserrat, sans-serif)
|
||||
);
|
||||
font-size: var(
|
||||
--markdown-editor-typography-font-size,
|
||||
var(--mdc-typography-subtitle1-font-size, 1rem)
|
||||
);
|
||||
font-weight: var(
|
||||
--markdown-editor-typography-font-weight,
|
||||
var(--mdc-typography-subtitle1-font-weight, 400)
|
||||
);
|
||||
letter-spacing: var(
|
||||
--markdown-editor-typography-letter-spacing,
|
||||
var(--mdc-typography-subtitle1-letter-spacing, 0.009375em)
|
||||
);
|
||||
}
|
||||
|
||||
.ProseMirror pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.ProseMirror a {
|
||||
color: var(--markdown-editor-typography-anchor-color, -webkit-link);
|
||||
text-decoration: var(--markdown-editor-typography-anchor-text-decoration);
|
||||
}
|
||||
|
||||
.ProseMirror-focused .ProseMirror-gapcursor {
|
||||
display: block;
|
||||
}
|
||||
shouting {
|
||||
all: unset; /* Remove inherited or conflicting styles */
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
color: red; }
|
||||
|
||||
.boring {
|
||||
background: grey;
|
||||
}
|
||||
`
|
||||
editorStyles
|
||||
];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.editorView.destroy
|
||||
}
|
||||
|
||||
|
||||
connectedCallback(): void {
|
||||
|
||||
super.connectedCallback();
|
||||
console.log('AppWrite added to the DOM')
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
if (this.editorView) {
|
||||
this.editorView.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected async firstUpdated() {
|
||||
console.log("Welcome to the compose page");
|
||||
await this.updateComplete;
|
||||
console.log('Rendered HTML:', this.shadowRoot?.innerHTML);
|
||||
|
||||
this.initializeEditor()
|
||||
if (!this.editorContainer) {
|
||||
errorReport('Editor container not here');
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private initializeEditor() {
|
||||
|
@ -289,17 +205,27 @@ export class AppWrite extends LitElement {
|
|||
return;
|
||||
}
|
||||
|
||||
/* this is a schema of initial content to pre-populate the editor
|
||||
with guidance */
|
||||
/* a prepopulated document of initial content to guide the user */
|
||||
|
||||
|
||||
let doc = customSchema.node("doc", null, [
|
||||
customSchema.node("paragraph", null, [customSchema.text("write anything")]),
|
||||
customSchema.node("boring_paragraph", null, [customSchema.text("you can't apply any marks to text in this boring paragraph")])
|
||||
let doc = customSchema.node('doc', null, [
|
||||
customSchema.node('heading', null, [customSchema.text('Título')]),
|
||||
|
||||
customSchema.node('blockquote', null, [
|
||||
customSchema.node('paragraph', null, [customSchema.text('"WEPA"')]),
|
||||
]),
|
||||
customSchema.node('paragraph', null, [customSchema.text('Escribe algo')]),
|
||||
customSchema.node('boring_paragraph', null, [
|
||||
customSchema.text('no se puede marcar ningún texto en párrafos aburridos como este. mira el <hr> debajo de este párafo. puedes colocar uno con Ctrl + h'),
|
||||
]),
|
||||
customSchema.node('horizontal_rule', null),
|
||||
customSchema.node('paragraph', null, [customSchema.text('Escribe mas aquí...')]),
|
||||
customSchema.node('paragraph', null, [customSchema.text('Presiona Shift + Space para colocar una estrella')]),
|
||||
customSchema.node('paragraph', null, [customSchema.text('Presiona Ctrl + g para marcar la selección con la marca "shouting" ')])
|
||||
|
||||
])
|
||||
|
||||
|
||||
if (!doc) {
|
||||
console.error("failed to create initial document")
|
||||
return;
|
||||
|
@ -307,8 +233,10 @@ export class AppWrite extends LitElement {
|
|||
|
||||
|
||||
|
||||
/* here i create a state with doc as the schema,
|
||||
which includes a couple */
|
||||
/* here i create a state with doc to,
|
||||
which places the prepopulated document of content
|
||||
and include history and keymap as plugins
|
||||
*/
|
||||
|
||||
const state = EditorState.create({
|
||||
doc: doc,
|
||||
|
@ -325,48 +253,27 @@ export class AppWrite extends LitElement {
|
|||
});
|
||||
|
||||
|
||||
/* this */
|
||||
|
||||
|
||||
let view = new EditorView(this.editorContainer, {
|
||||
this.editorView = new EditorView(this.editorContainer, {
|
||||
state,
|
||||
dispatchTransaction(transaction) {
|
||||
dispatchTransaction: (transaction) => {
|
||||
console.log('Document size went from', transaction.before.content.size, "to",
|
||||
transaction.doc.content.size
|
||||
)
|
||||
let newState = view.state.apply(transaction)
|
||||
view.updateState(newState)
|
||||
let newState = this.editorView.state.apply(transaction);
|
||||
this.editorView.updateState(newState);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
console.log(state)
|
||||
|
||||
|
||||
}
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
console.log('AppWrite added to the DOM')
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
if (this.editorView) {
|
||||
this.editorView.destroy();
|
||||
this.editorView = null!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<main><app-header ?enableBack="${true}"></app-header>
|
||||
|
||||
|
||||
|
||||
<div class="ProseMirror"></div>
|
||||
</main>
|
||||
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import { css } from "lit"
|
||||
|
||||
export const editorStyles = css` {
|
||||
export const editorStyles = css`
|
||||
|
||||
|
||||
|
||||
|
||||
.ProseMirror {
|
||||
background: white;
|
||||
color: black;
|
||||
:host .ProseMirror {
|
||||
background: black;
|
||||
color: white;
|
||||
background-clip: padding-box;
|
||||
padding: 5px 0;
|
||||
position: relative;
|
||||
|
@ -48,7 +45,6 @@ export const editorStyles = css` {
|
|||
.ProseMirror-focused .ProseMirror-gapcursor {
|
||||
display: block;
|
||||
}
|
||||
|
||||
shouting {
|
||||
all: unset; /* Remove inherited or conflicting styles */
|
||||
font-weight: bold;
|
||||
|
@ -58,21 +54,11 @@ export const editorStyles = css` {
|
|||
.boring {
|
||||
background: grey;
|
||||
}
|
||||
|
||||
.plus {
|
||||
position: absolute;
|
||||
|
||||
padding: 8px;
|
||||
background-color: #4CAF50;
|
||||
color: red;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.plus:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
font-style: italic;
|
||||
border-left: 2px solid gray;
|
||||
padding-left: 10px;
|
||||
color: darkgray;
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue