@standardnotes/rich-text 1.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +3 -0
- package/.eslintignore +5 -0
- package/.eslintrc +15 -0
- package/CHANGELOG.md +92 -0
- package/LICENSE +661 -0
- package/README.md +31 -0
- package/dist/dist.css +3246 -0
- package/dist/dist.css.map +1 -0
- package/dist/dist.js +2 -0
- package/dist/dist.js.map +1 -0
- package/dist/font/summernote.eot +0 -0
- package/dist/font/summernote.ttf +0 -0
- package/dist/font/summernote.woff +0 -0
- package/dist/font/summernote.woff2 +0 -0
- package/dist/index.html +1 -0
- package/dist/vendor.css +3249 -0
- package/dist/vendor.js +2 -0
- package/dist/vendor.js.LICENSE.txt +7 -0
- package/editor.index.ejs +19 -0
- package/ext.json.sample +8 -0
- package/package.json +47 -0
- package/plus_editor_bar.png +0 -0
- package/src/main.js +321 -0
- package/src/main.scss +169 -0
- package/vendor/font/summernote.eot +0 -0
- package/vendor/font/summernote.ttf +0 -0
- package/vendor/font/summernote.woff +0 -0
- package/vendor/font/summernote.woff2 +0 -0
- package/webpack.config.js +66 -0
- package/webpack.dev.js +23 -0
- package/webpack.prod.js +7 -0
package/editor.index.ejs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<base target="_blank">
|
|
6
|
+
<meta charset="UTF-8">
|
|
7
|
+
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
|
8
|
+
<title><%= htmlWebpackPlugin.options.title %></title>
|
|
9
|
+
<link rel="stylesheet" href="vendor.css">
|
|
10
|
+
<script src="vendor.js"></script>
|
|
11
|
+
</head>
|
|
12
|
+
|
|
13
|
+
<body>
|
|
14
|
+
<div class="sn-component" id="plus-editor">
|
|
15
|
+
<div id="summernote" name="editor"></div>
|
|
16
|
+
</div>
|
|
17
|
+
</body>
|
|
18
|
+
|
|
19
|
+
</html>
|
package/ext.json.sample
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@standardnotes/rich-text",
|
|
3
|
+
"version": "1.8.6",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "A rich text editor for Standard Notes",
|
|
8
|
+
"main": "dist/dist.js",
|
|
9
|
+
"author": "Standard Notes.",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"skip:lint": "eslint --ext .js .",
|
|
12
|
+
"lint:fix": "eslint --ext .js . --fix",
|
|
13
|
+
"build": "webpack --config webpack.prod.js",
|
|
14
|
+
"start": "webpack serve --config webpack.dev.js --progress --hot",
|
|
15
|
+
"test": "echo \"Error: no test specified\" && exit 0"
|
|
16
|
+
},
|
|
17
|
+
"sn": {
|
|
18
|
+
"main": "dist/index.html"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@standardnotes/component-relay": "standardnotes/component-relay#839ff5db9bc92db9d42cad8d202ddc4df729597d"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@babel/cli": "^7.13.0",
|
|
25
|
+
"@babel/core": "^7.13.8",
|
|
26
|
+
"@babel/eslint-parser": "^7.13.8",
|
|
27
|
+
"@babel/preset-env": "^7.13.8",
|
|
28
|
+
"@standardnotes/eslint-config-extensions": "1.0.1",
|
|
29
|
+
"bootstrap": "3.4.1",
|
|
30
|
+
"css-loader": "^5.1.0",
|
|
31
|
+
"dompurify": "^2.2.9",
|
|
32
|
+
"eslint": "^7.20.0",
|
|
33
|
+
"html-webpack-plugin": "^5.2.0",
|
|
34
|
+
"jquery": "^3.5.1",
|
|
35
|
+
"mini-css-extract-plugin": "^1.3.9",
|
|
36
|
+
"node-sass": "*",
|
|
37
|
+
"sass-loader": "^11.0.1",
|
|
38
|
+
"sn-stylekit": "^2.1.1",
|
|
39
|
+
"style-loader": "^2.0.0",
|
|
40
|
+
"summernote": "^0.8.18",
|
|
41
|
+
"webpack": "*",
|
|
42
|
+
"webpack-cli": "*",
|
|
43
|
+
"webpack-dev-server": "*",
|
|
44
|
+
"webpack-merge": "^5.8.0",
|
|
45
|
+
"webpack-merge-and-include-globally": "^2.3.3"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
Binary file
|
package/src/main.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
2
|
+
let componentRelay
|
|
3
|
+
let workingNote, clientData
|
|
4
|
+
let lastValue, lastUUID
|
|
5
|
+
let ignoreTextChange = false
|
|
6
|
+
let newNoteLoad = true,
|
|
7
|
+
didToggleFullScreen = false
|
|
8
|
+
|
|
9
|
+
const blockString = [
|
|
10
|
+
'address',
|
|
11
|
+
'article',
|
|
12
|
+
'aside',
|
|
13
|
+
'blockquote',
|
|
14
|
+
'details',
|
|
15
|
+
'dialog',
|
|
16
|
+
'dd',
|
|
17
|
+
'div',
|
|
18
|
+
'dl',
|
|
19
|
+
'dt',
|
|
20
|
+
'fieldset',
|
|
21
|
+
'figcaption',
|
|
22
|
+
'figure',
|
|
23
|
+
'footer',
|
|
24
|
+
'form',
|
|
25
|
+
'form',
|
|
26
|
+
'h1',
|
|
27
|
+
'h2',
|
|
28
|
+
'h3',
|
|
29
|
+
'h4',
|
|
30
|
+
'h5',
|
|
31
|
+
'h6',
|
|
32
|
+
'header',
|
|
33
|
+
'hgroup',
|
|
34
|
+
'hr',
|
|
35
|
+
'li',
|
|
36
|
+
'main',
|
|
37
|
+
'nav',
|
|
38
|
+
'ol',
|
|
39
|
+
'p',
|
|
40
|
+
'pre',
|
|
41
|
+
'section',
|
|
42
|
+
'table',
|
|
43
|
+
'ul',
|
|
44
|
+
].join(', ')
|
|
45
|
+
|
|
46
|
+
const getElementHeight = (el) => {
|
|
47
|
+
let elHeight = el.offsetHeight
|
|
48
|
+
elHeight += parseInt(window.getComputedStyle(el).getPropertyValue('margin-top'))
|
|
49
|
+
elHeight += parseInt(window.getComputedStyle(el).getPropertyValue('margin-bottom'))
|
|
50
|
+
return elHeight
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function loadComponentRelay() {
|
|
54
|
+
componentRelay = new ComponentRelay({
|
|
55
|
+
targetWindow: window,
|
|
56
|
+
onReady: () => {
|
|
57
|
+
const platform = componentRelay.platform
|
|
58
|
+
if (platform) {
|
|
59
|
+
document.body.classList.add(platform)
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
handleRequestForContentHeight: () => {
|
|
63
|
+
const editor = document.querySelector('.note-editable')
|
|
64
|
+
const toolbar = document.querySelector('.note-toolbar')
|
|
65
|
+
if (!editor || !toolbar) {
|
|
66
|
+
return undefined
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let height = getElementHeight(toolbar) + 40
|
|
70
|
+
for (const child of editor.children) {
|
|
71
|
+
height += getElementHeight(child)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return height
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
componentRelay.streamContextItem((note) => {
|
|
79
|
+
onReceivedNote(note)
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function strip(html) {
|
|
84
|
+
const tmp = document.implementation.createHTMLDocument('New').body
|
|
85
|
+
tmp.innerHTML = html
|
|
86
|
+
return tmp.textContent || tmp.innerText || ''
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function truncateString(string, limit = 90) {
|
|
90
|
+
if (string.length <= limit) {
|
|
91
|
+
return string
|
|
92
|
+
} else {
|
|
93
|
+
return string.substring(0, limit) + '...'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function save() {
|
|
98
|
+
if (workingNote) {
|
|
99
|
+
// Be sure to capture this object as a variable, as workingNote may be
|
|
100
|
+
// reassigned in `streamContextItem`, so by the time you modify it in
|
|
101
|
+
// the presave block, it may not be the same object anymore, so the
|
|
102
|
+
// presave values will not be applied to the right object, and it will
|
|
103
|
+
// save incorrectly.
|
|
104
|
+
const note = workingNote
|
|
105
|
+
|
|
106
|
+
componentRelay.saveItemWithPresave(note, () => {
|
|
107
|
+
lastValue = $('#summernote').summernote('code')
|
|
108
|
+
note.clientData = clientData
|
|
109
|
+
|
|
110
|
+
note.content.text = lastValue
|
|
111
|
+
note.content.preview_plain = truncateString(strip(lastValue))
|
|
112
|
+
note.content.preview_html = null
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function onReceivedNote(note) {
|
|
118
|
+
if (note.uuid !== lastUUID) {
|
|
119
|
+
// Note changed, reset last values
|
|
120
|
+
lastValue = null
|
|
121
|
+
newNoteLoad = true
|
|
122
|
+
lastUUID = note.uuid
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
workingNote = note
|
|
126
|
+
|
|
127
|
+
// Only update UI on non-metadata updates.
|
|
128
|
+
if (note.isMetadataUpdate) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
clientData = note.clientData
|
|
133
|
+
let newText = note.content.text
|
|
134
|
+
|
|
135
|
+
$('.note-editable').attr('spellcheck', JSON.stringify(note.content.spellcheck))
|
|
136
|
+
|
|
137
|
+
if (newText == lastValue) {
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const summernote = $('#summernote')
|
|
142
|
+
if (summernote) {
|
|
143
|
+
ignoreTextChange = true
|
|
144
|
+
const isHtml = /<[a-z][\s\S]*>/i.test(newText)
|
|
145
|
+
|
|
146
|
+
if (!didToggleFullScreen) {
|
|
147
|
+
summernote.summernote('fullscreen.toggle')
|
|
148
|
+
didToggleFullScreen = true
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (newNoteLoad && !isHtml) {
|
|
152
|
+
newText = textToHTML(newText)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let renderNote = false
|
|
156
|
+
const isUnsafeContent = checkIfUnsafeContent(newText)
|
|
157
|
+
|
|
158
|
+
if (isUnsafeContent) {
|
|
159
|
+
const currentNotePreferences = getCurrentNotePreferences()
|
|
160
|
+
if (!currentNotePreferences) {
|
|
161
|
+
showUnsafeContentAlert().then((result) => {
|
|
162
|
+
if (result) {
|
|
163
|
+
setNotePreferences('trustUnsafeContent', result)
|
|
164
|
+
renderNote = result
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
} else {
|
|
168
|
+
renderNote = currentNotePreferences.trustUnsafeContent || false
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
renderNote = true
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* If the user decides not to continue rendering the note,
|
|
176
|
+
* clear the editor and disable it.
|
|
177
|
+
*/
|
|
178
|
+
if (!renderNote) {
|
|
179
|
+
summernote.summernote('code', '')
|
|
180
|
+
summernote.summernote('disable')
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
summernote.summernote('enable')
|
|
185
|
+
summernote.summernote('code', newText)
|
|
186
|
+
|
|
187
|
+
if (newNoteLoad) {
|
|
188
|
+
// Clears history but keeps note contents. Note that this line will
|
|
189
|
+
// trigger a summernote.change event, so be sure to do this inside a
|
|
190
|
+
// `ignoreTextChange` block.
|
|
191
|
+
summernote.summernote('commit')
|
|
192
|
+
newNoteLoad = false
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
ignoreTextChange = false
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function getNotePreferences() {
|
|
200
|
+
return componentRelay.getComponentDataValueForKey('notes') || {}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function getCurrentNotePreferences() {
|
|
204
|
+
const notesPreferences = getNotePreferences()
|
|
205
|
+
return notesPreferences[lastUUID]
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function setNotePreferences(key, value) {
|
|
209
|
+
const notesPreferences = getNotePreferences()
|
|
210
|
+
notesPreferences[lastUUID] = {
|
|
211
|
+
[key]: value,
|
|
212
|
+
}
|
|
213
|
+
componentRelay.setComponentDataValueForKey('notes', notesPreferences)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Checks if the content contains at least one script tag.
|
|
218
|
+
*/
|
|
219
|
+
function checkIfUnsafeContent(content) {
|
|
220
|
+
const doc = new DOMParser().parseFromString(`<body>${content}</body>`, 'text/html')
|
|
221
|
+
return Array.from(doc.body.childNodes).some((node) => node.nodeName == 'SCRIPT')
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function showUnsafeContentAlert() {
|
|
225
|
+
const text =
|
|
226
|
+
'We’ve detected that this note contains a script or code snippet which may be unsafe to execute. ' +
|
|
227
|
+
'Scripts executed in the editor have the ability to impersonate as the editor to Standard Notes. ' +
|
|
228
|
+
'Press Continue to mark this script as safe and proceed, or Cancel to avoid rendering this note.'
|
|
229
|
+
|
|
230
|
+
return new Promise((resolve) => {
|
|
231
|
+
const alert = new Stylekit.SKAlert({
|
|
232
|
+
title: null,
|
|
233
|
+
text,
|
|
234
|
+
buttons: [
|
|
235
|
+
{
|
|
236
|
+
text: 'Cancel',
|
|
237
|
+
style: 'neutral',
|
|
238
|
+
action: function () {
|
|
239
|
+
resolve(false)
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
text: 'Continue',
|
|
244
|
+
style: 'danger',
|
|
245
|
+
action: function () {
|
|
246
|
+
resolve(true)
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
})
|
|
251
|
+
alert.present()
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function loadEditor() {
|
|
256
|
+
$('#summernote').summernote({
|
|
257
|
+
height: 500, // set editor height
|
|
258
|
+
minHeight: null, // set minimum height of editor
|
|
259
|
+
maxHeight: null, // set maximum height of editor
|
|
260
|
+
focus: true, // set focus to editable area after initializing summernote
|
|
261
|
+
tabDisable: true, // set tab interaction to note only
|
|
262
|
+
showDomainOnlyForAutolink: false, // set autolink to preserve whole link
|
|
263
|
+
toolbar: [
|
|
264
|
+
// [groupName, [list of button]]
|
|
265
|
+
['para', ['style']],
|
|
266
|
+
['style', ['bold', 'italic', 'underline', 'strikethrough', 'clear']],
|
|
267
|
+
['fontsize', ['fontsize', 'fontname']],
|
|
268
|
+
['color', ['color']],
|
|
269
|
+
['para', ['ul', 'ol', 'paragraph']],
|
|
270
|
+
['height', ['height']],
|
|
271
|
+
['insert', ['table', 'link', 'hr', 'picture', 'video']],
|
|
272
|
+
['misc', ['codeview', 'help']],
|
|
273
|
+
],
|
|
274
|
+
fontNames: [
|
|
275
|
+
'Arial',
|
|
276
|
+
'Arial Black',
|
|
277
|
+
'Comic Sans MS',
|
|
278
|
+
'Courier New',
|
|
279
|
+
'Helvetica Neue',
|
|
280
|
+
'Helvetica',
|
|
281
|
+
'Impact',
|
|
282
|
+
'Lucida Grande',
|
|
283
|
+
'Monospace',
|
|
284
|
+
'Roboto',
|
|
285
|
+
'system-ui',
|
|
286
|
+
'Tahoma',
|
|
287
|
+
'Times New Roman',
|
|
288
|
+
'Verdana',
|
|
289
|
+
],
|
|
290
|
+
callbacks: {
|
|
291
|
+
onInit: function () {},
|
|
292
|
+
onImageUpload: function () {
|
|
293
|
+
alert(
|
|
294
|
+
'Embedding encrypted images directly inside the editor is not presently supported. You can attach files to be outside the editor instead. For embedding images directly inside this note, use the Image button in the toolbar and insert the URL of an image hosted externally (outside of Standard Notes). For more information, visit https://standardnotes.com/help/36/how-do-i-attach-encrypted-files-to-my-notes.',
|
|
295
|
+
)
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
// summernote.change
|
|
301
|
+
$('#summernote').on('summernote.change', function () {
|
|
302
|
+
// Add RTL support when block-level elements are detect onchange.
|
|
303
|
+
document.querySelectorAll(blockString).forEach((element) => element.setAttribute('dir', 'auto'))
|
|
304
|
+
|
|
305
|
+
if (!ignoreTextChange) {
|
|
306
|
+
save()
|
|
307
|
+
}
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
$('textarea.note-codable').on('input', () => {
|
|
311
|
+
save()
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
loadEditor()
|
|
316
|
+
loadComponentRelay()
|
|
317
|
+
|
|
318
|
+
function textToHTML(text) {
|
|
319
|
+
return ((text || '') + '').replace(/\t/g, ' ').replace(/\r\n|\r|\n/g, '<br />')
|
|
320
|
+
}
|
|
321
|
+
})
|
package/src/main.scss
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
@import '~sn-stylekit/dist/stylekit.css';
|
|
2
|
+
|
|
3
|
+
body,
|
|
4
|
+
html {
|
|
5
|
+
font-family: sans-serif;
|
|
6
|
+
font-size: var(--sn-stylekit-base-font-size);
|
|
7
|
+
height: 100%;
|
|
8
|
+
margin: 0;
|
|
9
|
+
background-color: transparent;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#summernote {
|
|
13
|
+
flex: 1 1 auto;
|
|
14
|
+
width: 100%;
|
|
15
|
+
height: 100%;
|
|
16
|
+
min-height: 100%;
|
|
17
|
+
font-size: var(--sn-stylekit-font-size-editor);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#plus-editor {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
position: relative;
|
|
24
|
+
height: 100%;
|
|
25
|
+
font-size: var(--sn-stylekit-font-size-editor);
|
|
26
|
+
|
|
27
|
+
.note-editor.note-frame.fullscreen {
|
|
28
|
+
// On Mobile, resizing the webview to avoid keyboard causes the option bar to be offset because its position is fixed.
|
|
29
|
+
position: relative !important;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pre {
|
|
33
|
+
background-color: var(--sn-stylekit-contrast-background-color);
|
|
34
|
+
color: var(--sn-stylekit-contrast-foreground-color);
|
|
35
|
+
border-color: var(--sn-stylekit-contrast-border-color);
|
|
36
|
+
font-size: var(--sn-stylekit-font-size-p);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
a {
|
|
40
|
+
color: var(--sn-stylekit-info-color);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.note-editor {
|
|
44
|
+
-webkit-overflow-scrolling: touch;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.note-editor.fullscreen {
|
|
48
|
+
background-color: var(--sn-stylekit-background-color);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.note-editor.note-frame.fullscreen .note-editable {
|
|
52
|
+
background-color: var(--sn-stylekit-background-color);
|
|
53
|
+
color: var(--sn-stylekit-foreground-color);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.panel-default>.panel-heading {
|
|
57
|
+
background-color: var(--sn-stylekit-secondary-background-color);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.btn-default {
|
|
61
|
+
color: var(--sn-stylekit-secondary-foreground-color);
|
|
62
|
+
background-color: var(--sn-stylekit-secondary-background-color);
|
|
63
|
+
border-color: var(--sn-stylekit-secondary-border-color);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.panel-heading {
|
|
67
|
+
border-color: var(--sn-stylekit-border-color);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.dropdown-menu {
|
|
71
|
+
background-color: var(--sn-stylekit-background-color);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.dropdown-menu>li>a {
|
|
75
|
+
color: var(--sn-stylekit-foreground-color);
|
|
76
|
+
|
|
77
|
+
&:hover {
|
|
78
|
+
background-color: var(--sn-stylekit-contrast-background-color);
|
|
79
|
+
color: var(--sn-stylekit-contrast-foreground-color);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.note-codable {
|
|
84
|
+
caret-color: #cccccc;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.note-color-btn {
|
|
88
|
+
border-color: var(--sn-stylekit-border-color);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.note-color-reset {
|
|
92
|
+
background-color: var(--sn-stylekit-contrast-background-color);
|
|
93
|
+
color: var(--sn-stylekit-contrast-foreground-color);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.note-palette-title {
|
|
97
|
+
color: var(--sn-stylekit-info-color);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.modal-content {
|
|
101
|
+
background-color: var(--sn-stylekit-contrast-background-color);
|
|
102
|
+
color: var(--sn-stylekit-contrast-foreground-color);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.modal-header,
|
|
106
|
+
.modal-footer {
|
|
107
|
+
border-color: var(--sn-stylekit-contrast-border-color);
|
|
108
|
+
|
|
109
|
+
.btn-primary {
|
|
110
|
+
background-color: var(--sn-stylekit-info-color);
|
|
111
|
+
color: var(--sn-stylekit-info-contrast-color);
|
|
112
|
+
border-color: transparent;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
table {
|
|
117
|
+
border-color: var(--sn-stylekit-contrast-border-color);
|
|
118
|
+
background-color: var(--sn-stylekit-contrast-background-color);
|
|
119
|
+
color: var(--sn-stylekit-contrast-foreground-color);
|
|
120
|
+
|
|
121
|
+
th,
|
|
122
|
+
td {
|
|
123
|
+
border: 1px solid var(--sn-stylekit-contrast-border-color);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
tr:nth-child(2n) {
|
|
127
|
+
background-color: var(--sn-stylekit-background-color);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
label kbd {
|
|
133
|
+
background-color: var(--sn-stylekit-background-color);
|
|
134
|
+
background-color: var(--sn-stylekit-foreground-color);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.modal-header .close {
|
|
138
|
+
color: var(--sn-stylekit-foreground-color);
|
|
139
|
+
text-shadow: none;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.note-popover,
|
|
144
|
+
.note-popover .arrow {
|
|
145
|
+
background-color: var(--sn-stylekit-contrast-background-color);
|
|
146
|
+
color: var(--sn-stylekit-contrast-foreground-color);
|
|
147
|
+
|
|
148
|
+
a {
|
|
149
|
+
color: var(--sn-stylekit-info-color);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
button {
|
|
153
|
+
background-color: var(--sn-stylekit-background-color);
|
|
154
|
+
color: var(--sn-stylekit-foreground-color);
|
|
155
|
+
border-color: var(--sn-stylekit-border-color);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.note-editor.note-frame {
|
|
160
|
+
border: 0 !important;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.panel-default {
|
|
164
|
+
border: 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.panel {
|
|
168
|
+
border-radius: 0;
|
|
169
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
|
3
|
+
const MergeIntoSingleFilePlugin = require('webpack-merge-and-include-globally')
|
|
4
|
+
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
5
|
+
const CopyPlugin = require('copy-webpack-plugin')
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
entry: [path.resolve(__dirname, 'src', 'main.js'), path.resolve(__dirname, 'src', 'main.scss')],
|
|
9
|
+
output: {
|
|
10
|
+
path: path.join(__dirname, 'dist'),
|
|
11
|
+
filename: 'dist.js',
|
|
12
|
+
},
|
|
13
|
+
module: {
|
|
14
|
+
rules: [
|
|
15
|
+
{
|
|
16
|
+
test: /\.s[ac]ss$/i,
|
|
17
|
+
use: [
|
|
18
|
+
MiniCssExtractPlugin.loader,
|
|
19
|
+
'css-loader',
|
|
20
|
+
{
|
|
21
|
+
loader: 'sass-loader',
|
|
22
|
+
options: {
|
|
23
|
+
sassOptions: {
|
|
24
|
+
includePaths: ['src/main.scss'],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
plugins: [
|
|
33
|
+
new MiniCssExtractPlugin({
|
|
34
|
+
filename: 'dist.css',
|
|
35
|
+
}),
|
|
36
|
+
new MergeIntoSingleFilePlugin({
|
|
37
|
+
files: {
|
|
38
|
+
'vendor.js': [
|
|
39
|
+
require.resolve('jquery/dist/jquery.min.js'),
|
|
40
|
+
require.resolve('bootstrap/dist/js/bootstrap.min.js'),
|
|
41
|
+
require.resolve('summernote/dist/summernote.min.js'),
|
|
42
|
+
require.resolve('@standardnotes/component-relay/dist/dist.js'),
|
|
43
|
+
require.resolve('dompurify/dist/purify.min.js'),
|
|
44
|
+
'node_modules/sn-stylekit/dist/stylekit.js',
|
|
45
|
+
],
|
|
46
|
+
'vendor.css': [
|
|
47
|
+
require.resolve('bootstrap/dist/css/bootstrap.min.css'),
|
|
48
|
+
require.resolve('summernote/dist/summernote.min.css'),
|
|
49
|
+
'node_modules/sn-stylekit/dist/stylekit.css',
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
}),
|
|
53
|
+
new HtmlWebpackPlugin({
|
|
54
|
+
title: 'Plus Editor',
|
|
55
|
+
template: 'editor.index.ejs',
|
|
56
|
+
}),
|
|
57
|
+
new CopyPlugin({
|
|
58
|
+
patterns: [
|
|
59
|
+
{
|
|
60
|
+
from: 'vendor',
|
|
61
|
+
to: '.',
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
}),
|
|
65
|
+
],
|
|
66
|
+
}
|
package/webpack.dev.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const { merge } = require('webpack-merge');
|
|
2
|
+
const config = require('./webpack.config.js');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
module.exports = merge(config, {
|
|
6
|
+
mode: 'development',
|
|
7
|
+
devtool: 'eval-cheap-module-source-map',
|
|
8
|
+
stats: {
|
|
9
|
+
colors: true
|
|
10
|
+
},
|
|
11
|
+
devServer: {
|
|
12
|
+
port: 8001,
|
|
13
|
+
contentBase: path.resolve(__dirname, 'dist'),
|
|
14
|
+
disableHostCheck: true,
|
|
15
|
+
historyApiFallback: true,
|
|
16
|
+
watchOptions: { aggregateTimeout: 300, poll: 1000 },
|
|
17
|
+
headers: {
|
|
18
|
+
'Access-Control-Allow-Origin': '*',
|
|
19
|
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
|
20
|
+
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
});
|