Skip to content

Commit 9978158

Browse files
committed
Fix bugs with package management, fix pasting from Chrome, add <details> and <summary> editing
1 parent 15a9de1 commit 9978158

File tree

27 files changed

+515
-542
lines changed

27 files changed

+515
-542
lines changed

@webwriter/app-desktop/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@webwriter/app-desktop",
3-
"version": "0.8.2",
3+
"version": "0.8.3",
44
"description": "Windows/Mac/Linux version of WebWriter",
55
"private": true,
66
"author": "Frederic Salmen <frederic@fsalmen.de>",

@webwriter/app-desktop/src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

@webwriter/app-desktop/src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "webwriter"
3-
version = "0.8.2"
3+
version = "0.8.3"
44
description = "Windows/Mac/Linux version of WebWriter"
55
authors = ["Frederic Salmen <frederic@fsalmen.de>"]
66
license = "UNLICENSED"

@webwriter/core/localization/generated/de.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,5 +413,7 @@
413413
'spaceKey': `Leertaste`,
414414
'tabKey': `⭾ Tab`,
415415
'upKey': `↑ Hoch`,
416+
's3b3ea038c5d3bb06': `Division`,
417+
'se6cdad455e2d8c02': `Insert a division`,
416418
};
417419

@webwriter/core/model/environment/tauri.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,19 @@ export async function search(text: string, params?: {size?: number, from?: numbe
173173
export async function pm(command: string, commandArgs: string[] = [], json=true, cwd?: string) {
174174
const cmdArgs = [command, ...(json ? ["--json"]: []), ...commandArgs]
175175
const opts = cwd? {cwd}: {}
176+
console.info(`[TAURI] ${cwd? cwd: await appDir()}> bin/yarn ${[...cmdArgs, "--mutex file"].join(" ")}`)
176177
const output = await Command.sidecar("bin/yarn", [...cmdArgs, "--mutex file"], opts).execute()
177178
if(output.stderr) {
178-
const err = output.stderr.split("\n").map((e: any) => JSON.parse(e))
179-
const errors = err.filter((e: any) => e.type === "error")
180-
const warnings = err.filter((e: any) => e.type === "warning")
179+
const err = output.stderr.split("\n").map((e: any) => {
180+
try {
181+
console.error(JSON.parse(e))
182+
}
183+
catch(err) {
184+
console.error(e)
185+
}
186+
})
187+
const errors = err.filter((e: any) => e?.type === "error")
188+
const warnings = err.filter((e: any) => e?.type === "warning")
181189
warnings.forEach((w: any) => console.warn(w.data))
182190
if(err?.some((e: any) => e?.type === "error")) {
183191
throw err

@webwriter/core/model/schemas/packageschema/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ const PackageObjectSchema = z.object({
386386
imports: z.record(z.string().startsWith("#"), z.record(z.string())).optional(),
387387
editingConfig: EditingConfig.optional(),
388388
installed: z.boolean().optional().default(false),
389-
outdated: z.boolean().optional().default(false),
389+
latest: SemVer.schema.optional(),
390390
imported: z.boolean().optional().default(false),
391391
watching: z.boolean().optional().default(false),
392392
reloadCount: z.number().optional().default(0),

@webwriter/core/model/schemas/resourceschema/editingstyles.css

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ html::-webkit-scrollbar-button:vertical:single-button:increment:disabled {
5959
border-color: var(--sl-color-gray-400) transparent transparent transparent;
6060
}
6161

62+
* {
63+
outline: none;
64+
}
65+
6266
a:not([href]) {
6367
text-decoration: underline;
6468
color: #0000EE;
@@ -145,25 +149,43 @@ figure.ProseMirror-selectednode::before {
145149
-webkit-user-select: none !important;
146150
}
147151

148-
.ww-widget[editable]::after {
152+
.ProseMirror > :not(.ProseMirror-widget) {
153+
position: relative;
154+
}
155+
156+
.ProseMirror > :not(.ProseMirror-widget)::after {
149157
content: "";
150158
position: absolute;
151-
right: -14px;
159+
right: -18px;
152160
top: 0;
153-
width: 6px;
161+
border-right: 6px solid transparent;
154162
background: none;
155163
height: 100%;
156-
border-radius: 4px;
164+
cursor: pointer;
165+
width: 20px;
157166
}
158167

159-
.ww-widget[editable]:hover::after {
160-
background: var(--sl-color-primary-300);
168+
.ProseMirror *:not([data-ww-inline]):hover {
169+
outline: 1px dotted var(--sl-color-gray-400);
170+
outline-offset: 2px;
171+
}
172+
/*
173+
.ProseMirror > *:hover::after {
174+
border-color: var(--sl-color-gray-100);
161175
}
162176
163-
.ww-widget[editable][data-ww-selected]::after {
164-
background: var(--sl-color-primary-400);
177+
.ProseMirror > *:is([data-ww-selected], :has([data-ww-selected]))::after {
178+
border-color: var(--sl-color-gray-200);
179+
}
180+
181+
.ProseMirror > *:is([data-ww-selected]:hover, :has([data-ww-selected]:hover))::after {
182+
border-color: var(--sl-color-gray-300);
165183
}
166184
185+
.ww-widget[editable][data-ww-deleting]::after {
186+
border-color: var(--sl-color-danger-400);
187+
}*/
188+
167189
.ww-widget[editable][data-ww-deleting]::before {
168190
content: "";
169191
position: absolute;
@@ -177,10 +199,6 @@ figure.ProseMirror-selectednode::before {
177199
height: 100%;
178200
}
179201

180-
.ww-widget[editable][data-ww-deleting]::after {
181-
background: var(--sl-color-danger-400);
182-
}
183-
184202
.ww-widget#ww_preview {
185203
position: relative;
186204
display: block;

@webwriter/core/model/schemas/resourceschema/htmlelementspec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export function toAttributes(node: Node | Attrs, extraAttrs?: Attrs) {
173173
const attrSpec: (k: string) => AttributeSpec & {private?: boolean} | undefined = (k: string) => complex? (node.type?.spec?.attrs ?? {})[k]: {}
174174
for (const [k, v] of Object.entries(attrs)) {
175175
const spec = attrSpec(k)
176-
if(k !== "data" && v !== undefined && (spec?.default !== v) && !spec?.private) {
176+
if(k !== "data" && v && (spec?.default !== v) && !spec?.private) {
177177
outputAttrs[k] = Array.isArray(v)? v.join(" "): v
178178
}
179179
if(k === "data") {

@webwriter/core/model/schemas/resourceschema/plugins/base.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,18 @@ export const basePlugin = () => ({
100100
content: "text | phrasing*",
101101
whitespace: "pre"
102102
}),
103+
div: HTMLElementSpec({
104+
tag: "div",
105+
group: "flow palpable",
106+
content: "flow*"
107+
}),
103108
pre: HTMLElementSpec({
104109
tag: "pre",
105110
group: "flow palpable",
106111
content: "text | phrasing*",
107112
whitespace: "pre"
108113
}),
109-
unknownElement: {
114+
/*unknownElement: {
110115
attrs: {
111116
tagName: {},
112117
otherAttrs: {default: {}}
@@ -133,7 +138,7 @@ export const basePlugin = () => ({
133138
"data-ww-editing": CustomElementName.safeParse(node.attrs.tagName).success? "unknowncustom": "unknownbuiltin",
134139
"data-ww-tagname": node.attrs.tagName
135140
}]
136-
},
141+
},*/
137142
},
138143
topNode: "explorable",
139144
keymap: baseKeymap,
Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,96 @@
1+
import { TextSelection, Command, EditorState, NodeSelection, AllSelection } from "prosemirror-state";
12
import { SchemaPlugin } from ".";
3+
import { range } from "../../../../utility";
24
import { HTMLElementSpec } from "../htmlelementspec";
5+
import {Node, ResolvedPos, NodeType, Attrs, NodeRange, Fragment} from "prosemirror-model"
6+
import {canSplit, liftTarget} from "prosemirror-transform"
37

4-
export const modalPlugin = () => ({
5-
dialog: HTMLElementSpec({
6-
tag: "dialog",
7-
group: "flow sectioningroot",
8-
content: "flow*",
9-
attrs: {
10-
open: {default: undefined}
11-
}
12-
}),
13-
details: HTMLElementSpec({
14-
tag: "details",
15-
group: "flow sectioningroot interactive palpable",
16-
content: `summary flow*`,
17-
attrs: {
18-
open: {default: undefined}
8+
export function getNodePath($pos: ResolvedPos, excludeRoot=true) {
9+
return range($pos.depth + 1).map(k => $pos.node(k)).slice(excludeRoot? 1: 0)
10+
}
11+
12+
export function getPosPath($pos: ResolvedPos, excludeRoot=true) {
13+
return range($pos.depth + 1).map(k => $pos.before(k + 1)).slice(excludeRoot? 1: 0)
14+
}
15+
16+
export function findAncestor($pos: ResolvedPos, predicate: (value: [number, Node], index: number, array: [number, Node][]) => boolean) {
17+
const nodePath = getNodePath($pos)
18+
const posPath = getPosPath($pos)
19+
return posPath.map((pos, i) => [pos, nodePath[i]] as [number, Node]).find(predicate) ?? []
20+
}
21+
22+
export function ancestorOfType($pos: ResolvedPos, type: string) {
23+
return findAncestor($pos, ([_, node]) => node?.type.name === type)
24+
}
25+
26+
function selectDetailsContent(split=false): Command {
27+
return (state, dispatch, view) => {
28+
const {selection, doc} = state
29+
const pType = state.schema.nodes["p"]!
30+
const [detailsPos, details] = ancestorOfType(selection.$from, "details")
31+
const [summaryPos, summary] = ancestorOfType(selection.$from, "summary")
32+
const nodePath = getNodePath(selection.$from)
33+
if(details && summary && split) {
34+
35+
let tr = state.tr.setNodeAttribute(detailsPos! - 1, "open", true)
36+
tr = tr.deleteSelection()
37+
tr = tr.split(tr.selection.from, undefined, [{type: pType}])
38+
dispatch && dispatch(tr)
39+
return true
1940
}
20-
}),
21-
summary: HTMLElementSpec({
22-
tag: "summary",
23-
content: "heading"
24-
})
41+
return false
42+
}
43+
}
44+
45+
export const modalPlugin = () => ({
46+
nodes: {
47+
dialog: HTMLElementSpec({
48+
tag: "dialog",
49+
group: "flow sectioningroot",
50+
content: "flow*",
51+
attrs: {
52+
open: {default: undefined}
53+
}
54+
}),
55+
details: HTMLElementSpec({
56+
tag: "details",
57+
group: "flow sectioningroot interactive palpable",
58+
content: `summary flow*`,
59+
attrs: {
60+
open: {default: undefined}
61+
}
62+
}),
63+
summary: HTMLElementSpec({
64+
tag: "summary",
65+
content: "phrasing*" // simplified until phrase editing is fixed
66+
})
67+
},
68+
keymap: {
69+
"Enter": selectDetailsContent(true),
70+
"ArrowDown": selectDetailsContent(),
71+
"Backspace": (state, dispatch, view) => {
72+
const {selection, doc} = state
73+
const [summaryPos, summary] = ancestorOfType(selection.$from, "summary")
74+
if(summary && selection.from === summaryPos) {
75+
76+
}
77+
/*
78+
console.log(getNodePath(selection.$from), getPosPath(selection.$from))
79+
const [detailsPos, details] = ancestorOfType(selection.$from, "details")
80+
const [summaryPos, summary] = detailsPos? [
81+
detailsPos + 1,
82+
details?.child(0).type.name === "summary"? details?.child(0): undefined
83+
]: []
84+
const open = details?.attrs.open
85+
console.log(details, summaryPos, selection.from)
86+
if(details && summaryPos !== undefined && selection.from === summaryPos) {
87+
console.log("backspace handled")
88+
let tr = state.tr.setSelection(TextSelection.create(doc, selection.from - 2))
89+
90+
dispatch && dispatch(tr)
91+
return true
92+
}*/
93+
return false
94+
},
95+
}
2596
} as SchemaPlugin)

0 commit comments

Comments
 (0)