@tenjuu99/blog 0.2.6 → 0.2.8
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/bin/dev-server +2 -1
- package/bin/new +1 -10
- package/lib/helper.js +8 -6
- package/lib/pageData.js +1 -0
- package/lib/server.js +1 -1
- package/lib/tryServer.js +3 -0
- package/package.json +1 -1
- package/src-sample/css/editor.css +50 -35
- package/src-sample/helper/index.js +115 -0
- package/src-sample/js/editor.js +19 -5
- package/src-sample/js/error.js +8 -0
- package/src-sample/pages/500.md +5 -0
- package/src-sample/pages/editor.md +2 -0
- package/src-sample/pages/notfound.md +1 -0
- package/src-sample/server/get_editor_target.js +5 -1
- package/src-sample/server/preview.js +6 -0
- package/src-sample/template/default.html +4 -1
- package/src-sample/template/editor.html +23 -27
- package/helper/index.js +0 -116
package/bin/dev-server
CHANGED
|
@@ -9,6 +9,7 @@ import { fileURLToPath } from 'url';
|
|
|
9
9
|
|
|
10
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
11
|
const libDir = path.dirname(__filename) + '/../lib/'
|
|
12
|
+
const binDir = path.dirname(__filename) + '/../bin/'
|
|
12
13
|
|
|
13
14
|
watchers.push({
|
|
14
15
|
paths: srcDir,
|
|
@@ -38,7 +39,7 @@ watch()
|
|
|
38
39
|
let childProcess = null
|
|
39
40
|
|
|
40
41
|
const proceed = () => {
|
|
41
|
-
const child = spawn('node', [
|
|
42
|
+
const child = spawn('node', [`${binDir}server`])
|
|
42
43
|
console.log(`start process. PID(parent): ${process.pid}, PID(child): ${child.pid}`)
|
|
43
44
|
|
|
44
45
|
child.stdout.on('data', (data) => {
|
package/bin/new
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
|
|
3
|
-
mkdir -p "$(pwd)/src/pages"
|
|
4
|
-
echo "create src/pages"
|
|
5
|
-
mkdir -p "$(pwd)/src/template"
|
|
6
|
-
echo "create src/template"
|
|
7
|
-
mkdir -p "$(pwd)/src/css"
|
|
8
|
-
echo "create src/css"
|
|
9
|
-
mkdir -p "$(pwd)/src/image"
|
|
10
|
-
echo "create src/image"
|
|
11
|
-
|
|
12
3
|
mkdir "$(pwd)/.cache"
|
|
13
4
|
echo "[]" > "$(pwd)/.cache/index.json"
|
|
14
5
|
|
|
@@ -24,7 +15,7 @@ echo '{
|
|
|
24
15
|
"src_dir": "src",
|
|
25
16
|
"dist_dir": "dist",
|
|
26
17
|
"distribute_raw": "image,js",
|
|
27
|
-
"helper": "
|
|
18
|
+
"helper": "index.js",
|
|
28
19
|
"editor_enable": true
|
|
29
20
|
}' > "$(pwd)/blog.json"
|
|
30
21
|
echo "create blog.json"
|
package/lib/helper.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import * as helperDefault from '../helper/index.js'
|
|
2
1
|
import config from './config.js'
|
|
3
|
-
import {
|
|
2
|
+
import { helperDir } from './dir.js'
|
|
4
3
|
|
|
5
|
-
let helper = {
|
|
4
|
+
let helper = {}
|
|
6
5
|
|
|
7
|
-
if (config
|
|
8
|
-
const
|
|
9
|
-
|
|
6
|
+
if (config.helper) {
|
|
7
|
+
const files = config.helper.split(',')
|
|
8
|
+
files.forEach(async file => {
|
|
9
|
+
const helperAdditional = await import(`${helperDir}/${file}`)
|
|
10
|
+
helper = Object.assign(helper, helperAdditional)
|
|
11
|
+
})
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export default helper
|
package/lib/pageData.js
CHANGED
|
@@ -24,6 +24,7 @@ const parse = (content, name, ext) => {
|
|
|
24
24
|
site_name: config.site_name,
|
|
25
25
|
url_base: config.url_base,
|
|
26
26
|
markdown: markdownReplaced,
|
|
27
|
+
markdown_not_parsed: markdownReplaced,
|
|
27
28
|
relative_path: config.relative_path || '',
|
|
28
29
|
template: 'default.html',
|
|
29
30
|
ext: 'html',
|
package/lib/server.js
CHANGED
|
@@ -61,7 +61,7 @@ const server = () => {
|
|
|
61
61
|
} catch (e) {
|
|
62
62
|
console.log(e)
|
|
63
63
|
console.log(styleText('red', `[${request.method}] 500`), request.url)
|
|
64
|
-
const errorContent = fs.readFileSync(`${distDir}/
|
|
64
|
+
const errorContent = fs.readFileSync(`${distDir}/500.html`)
|
|
65
65
|
response.writeHead(500)
|
|
66
66
|
response.end(errorContent)
|
|
67
67
|
}
|
package/lib/tryServer.js
CHANGED
|
@@ -22,6 +22,9 @@ const handlers = async (path) => {
|
|
|
22
22
|
* @param {http.ServerResponse} res
|
|
23
23
|
*/
|
|
24
24
|
const tryServer = async (path, req, res) => {
|
|
25
|
+
if (!fs.existsSync(serverDir)) {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
25
28
|
const handler = await handlers(path)
|
|
26
29
|
const method = req.method.toLowerCase()
|
|
27
30
|
if (handler && handler[method]) {
|
package/package.json
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
body {
|
|
2
2
|
background: #fafafa;
|
|
3
|
-
--container-max-width: 100%;
|
|
4
|
-
--container-min-width: 100%;
|
|
5
|
-
--container-width: 100%;
|
|
6
3
|
height: 100vh;
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
}
|
|
7
|
+
header {
|
|
8
|
+
text-align: center;
|
|
9
|
+
border-bottom: .1px solid #eee;
|
|
10
|
+
box-shadow: 1px 1px 3px #999;
|
|
7
11
|
}
|
|
8
12
|
main {
|
|
9
13
|
height: 100%;
|
|
10
|
-
margin: 0 auto
|
|
14
|
+
/*margin: 0 auto;*/
|
|
11
15
|
display: flex;
|
|
12
16
|
flex-direction: row;
|
|
13
17
|
justify-content: flex-start;
|
|
@@ -17,7 +21,7 @@ main.container {
|
|
|
17
21
|
}
|
|
18
22
|
.textareaAndPreview {
|
|
19
23
|
display: flex;
|
|
20
|
-
margin:
|
|
24
|
+
margin: 0;
|
|
21
25
|
border: 1px solid #666;
|
|
22
26
|
border-radius: 5px;
|
|
23
27
|
height: 100%;
|
|
@@ -28,19 +32,23 @@ main.container {
|
|
|
28
32
|
.editor {
|
|
29
33
|
display: flex;
|
|
30
34
|
flex-direction: column;
|
|
31
|
-
padding:
|
|
35
|
+
padding: 5px;
|
|
32
36
|
justify-content:center;
|
|
33
37
|
height: 100%;
|
|
34
38
|
/* width: 100%; */
|
|
35
|
-
margin: 0
|
|
39
|
+
margin: 0;
|
|
36
40
|
position: relative;
|
|
41
|
+
width: 100%;
|
|
37
42
|
left: 0;
|
|
38
43
|
flex-basis: 100%;
|
|
39
|
-
transition: flex-basis 0.3s;
|
|
40
44
|
}
|
|
41
45
|
.sidebar-close .editor {
|
|
42
|
-
flex-basis: 90
|
|
43
|
-
|
|
46
|
+
/*flex-basis: 90%;*/
|
|
47
|
+
margin-left: 20px;
|
|
48
|
+
}
|
|
49
|
+
.editor-options {
|
|
50
|
+
display: flex;
|
|
51
|
+
justify-content: space-between;
|
|
44
52
|
}
|
|
45
53
|
#editorTextArea {
|
|
46
54
|
resize: none;
|
|
@@ -58,7 +66,6 @@ main.container {
|
|
|
58
66
|
}
|
|
59
67
|
form select {
|
|
60
68
|
padding: 5px;
|
|
61
|
-
margin-top: 5px;
|
|
62
69
|
border-radius: 5px;
|
|
63
70
|
}
|
|
64
71
|
#previewContent {
|
|
@@ -80,64 +87,55 @@ form select {
|
|
|
80
87
|
width: 300px;
|
|
81
88
|
overflow: hidden;
|
|
82
89
|
left: 0;
|
|
83
|
-
background:
|
|
90
|
+
background: rgb(192, 198, 217);
|
|
84
91
|
height: 100%;
|
|
85
92
|
padding: 0;
|
|
86
93
|
overflow-y: hidden;
|
|
87
|
-
transition: left 0.3s, flex-basis 0.3s;
|
|
88
94
|
flex-basis: 300px;
|
|
89
95
|
position: relative;
|
|
96
|
+
z-index: 3;
|
|
97
|
+
word-break: break-all;
|
|
90
98
|
}
|
|
91
99
|
.sidebar-close .sidebar {
|
|
92
100
|
left: -290px;
|
|
93
|
-
transition: left 0.3s, flex-basis 0.3s;
|
|
94
101
|
flex-basis: 0;
|
|
95
102
|
}
|
|
96
103
|
.sidebar ul {
|
|
97
104
|
padding: 0;
|
|
98
|
-
margin: 0
|
|
99
|
-
left: 0;
|
|
100
|
-
transition: left 0.3s;
|
|
101
|
-
min-width: 180px;
|
|
102
|
-
max-width: 180px;
|
|
105
|
+
margin: 0;
|
|
103
106
|
}
|
|
104
107
|
.sidebar-close .sidebar ul {
|
|
105
108
|
position: absolute;
|
|
106
109
|
left: -290px;
|
|
107
110
|
transition: left 0.3s;
|
|
108
111
|
}
|
|
109
|
-
@media screen and (min-width: 1100px) {
|
|
110
|
-
}
|
|
111
|
-
@media screen and (min-width: 1400px) {
|
|
112
|
-
}
|
|
113
|
-
@media screen and (max-width: 600px) {
|
|
114
|
-
.sidebar {
|
|
115
|
-
flex-basis: 80%;
|
|
116
|
-
}
|
|
117
|
-
.sidebar.close {
|
|
118
|
-
flex-basis: 5%;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
112
|
.sidebar li {
|
|
122
113
|
list-style: none;
|
|
114
|
+
padding-left: 20px;
|
|
123
115
|
}
|
|
124
116
|
.sidebar a {
|
|
125
|
-
color: #
|
|
117
|
+
color: #666;
|
|
118
|
+
text-decoration: none;
|
|
119
|
+
}
|
|
120
|
+
.sidebar li:hover {
|
|
121
|
+
background: rgba(104, 117, 154, .3);
|
|
126
122
|
}
|
|
127
123
|
.sidebar-toggle {
|
|
128
124
|
cursor: pointer;
|
|
129
125
|
width: 20px;
|
|
130
126
|
height: 100%;
|
|
131
|
-
|
|
127
|
+
position: absolute;
|
|
128
|
+
right: 0;
|
|
132
129
|
}
|
|
133
130
|
.sidebar-close .sidebar-toggle {
|
|
134
131
|
position: fixed;
|
|
135
132
|
left: 0;
|
|
133
|
+
background: rgb(192, 198, 217);
|
|
136
134
|
}
|
|
137
135
|
.sidebar-toggle:hover:after {
|
|
138
136
|
position: absolute;
|
|
139
137
|
right: 0;
|
|
140
|
-
content: '
|
|
138
|
+
content: '';
|
|
141
139
|
height: 100%;
|
|
142
140
|
width: 20px;
|
|
143
141
|
background: rgba(255, 255,255, 0.3);
|
|
@@ -177,6 +175,12 @@ form select {
|
|
|
177
175
|
.sidebar-toggle {
|
|
178
176
|
display: none;
|
|
179
177
|
}
|
|
178
|
+
.sidebar {
|
|
179
|
+
flex-basis: 80%;
|
|
180
|
+
}
|
|
181
|
+
.sidebar.close {
|
|
182
|
+
flex-basis: 5%;
|
|
183
|
+
}
|
|
180
184
|
}
|
|
181
185
|
/**
|
|
182
186
|
* hamburger
|
|
@@ -185,6 +189,17 @@ form select {
|
|
|
185
189
|
display: none;
|
|
186
190
|
}
|
|
187
191
|
@media screen and (max-width: 600px) {
|
|
192
|
+
.sidebar-close .editor {
|
|
193
|
+
margin-left: 0;
|
|
194
|
+
margin: 0;
|
|
195
|
+
}
|
|
196
|
+
.editor-options {
|
|
197
|
+
margin-right: 50px;
|
|
198
|
+
}
|
|
199
|
+
.editor-options * {
|
|
200
|
+
display: flex;
|
|
201
|
+
flex-direction: column;
|
|
202
|
+
}
|
|
188
203
|
.hamburger-menu {
|
|
189
204
|
display: block;
|
|
190
205
|
}
|
|
@@ -208,7 +223,7 @@ form select {
|
|
|
208
223
|
height: 3px;
|
|
209
224
|
width: 25px;
|
|
210
225
|
border-radius: 3px;
|
|
211
|
-
background-color: #
|
|
226
|
+
background-color: #666666;
|
|
212
227
|
position: absolute;
|
|
213
228
|
transition: transform 0.3s, background-color 0.3s;
|
|
214
229
|
}
|
|
@@ -1,4 +1,119 @@
|
|
|
1
1
|
import { allData } from '@tenjuu99/blog/lib/indexer.js'
|
|
2
|
+
import { replaceVariablesFilter } from "@tenjuu99/blog/lib/filter.js";
|
|
3
|
+
import config from '@tenjuu99/blog/lib/config.js'
|
|
4
|
+
|
|
5
|
+
export function readIndex (filter = null) {
|
|
6
|
+
const data = Object.entries(allData)
|
|
7
|
+
.sort((a, b) => new Date(b[1].published) - new Date(a[1].published))
|
|
8
|
+
return filter
|
|
9
|
+
? data.filter(v => v[0].indexOf(filter) === 0).map(v => v[1])
|
|
10
|
+
: data.map(v => v[1])
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function dateFormat(dateString) {
|
|
14
|
+
const date = new Date(dateString)
|
|
15
|
+
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function render(text, variables) {
|
|
19
|
+
return replaceVariablesFilter(text, variables)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getPageData(name) {
|
|
23
|
+
return allData[name]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let indexedItemsSorted = null
|
|
27
|
+
export function indexedItems() {
|
|
28
|
+
if (indexedItemsSorted) {
|
|
29
|
+
return indexedItemsSorted
|
|
30
|
+
}
|
|
31
|
+
const sorted = readIndex()
|
|
32
|
+
.filter(v => v.index && v.published != '1970-01-01')
|
|
33
|
+
.sort((a, b) => new Date(a.published) - new Date(b.published))
|
|
34
|
+
let prev, next
|
|
35
|
+
for (const item of sorted) {
|
|
36
|
+
if (prev) {
|
|
37
|
+
prev.next = {
|
|
38
|
+
name: item.name,
|
|
39
|
+
published: item.published,
|
|
40
|
+
url: item.url,
|
|
41
|
+
title: item.title,
|
|
42
|
+
}
|
|
43
|
+
item.prev = {
|
|
44
|
+
name: prev.name,
|
|
45
|
+
published: prev.published,
|
|
46
|
+
url: prev.url,
|
|
47
|
+
title: prev.title,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
prev = item
|
|
51
|
+
}
|
|
52
|
+
indexedItemsSorted = sorted
|
|
53
|
+
return indexedItemsSorted
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 配列を再帰的に順不同リストに変換する
|
|
58
|
+
* @param {Array|string} arrayOrText
|
|
59
|
+
* @returns {mixed}
|
|
60
|
+
*/
|
|
61
|
+
export function arrayToList(arrayOrText) {
|
|
62
|
+
if (typeof arrayOrText === 'string') {
|
|
63
|
+
return `<li>${arrayOrText}</li>`
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(arrayOrText)) {
|
|
66
|
+
let resultListText = '<ul>'
|
|
67
|
+
for (const item of arrayOrText) {
|
|
68
|
+
if (Array.isArray(item)) {
|
|
69
|
+
resultListText += `<li>${arrayToList(item)}</li>`
|
|
70
|
+
} else {
|
|
71
|
+
resultListText += `<li>${item}</li>`
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
resultListText += '</ul>'
|
|
75
|
+
arrayOrText = resultListText
|
|
76
|
+
}
|
|
77
|
+
return arrayOrText
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function renderIndex(pages, nodate = 'nodate', headingTag = 'h3') {
|
|
81
|
+
if (!pages) {
|
|
82
|
+
pages = readIndex()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const renderList = {}
|
|
86
|
+
for (const page of pages) {
|
|
87
|
+
if (page.index) {
|
|
88
|
+
const url = config.relative_path ? config.relative_path + page.url : page.url
|
|
89
|
+
if (page.published === '1970-01-01') {
|
|
90
|
+
if (!renderList[nodate]) {
|
|
91
|
+
renderList[nodate] = []
|
|
92
|
+
}
|
|
93
|
+
renderList[nodate].push(`<a href="${url}">${page.title}</a>`)
|
|
94
|
+
continue
|
|
95
|
+
}
|
|
96
|
+
const published = new Date(page.published)
|
|
97
|
+
const year = `${published.getFullYear()}年`
|
|
98
|
+
const date = `${published.getMonth() +1}月${published.getDate()}日`
|
|
99
|
+
if (!renderList[year]) {
|
|
100
|
+
renderList[year] = []
|
|
101
|
+
}
|
|
102
|
+
renderList[year].push(`<a href="${url}">${page.title}</a> (${date})`)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const resultText = []
|
|
107
|
+
for (const key in renderList) {
|
|
108
|
+
resultText.push(`<${headingTag}>${key}</${headingTag}>`)
|
|
109
|
+
if (Array.isArray(renderList[key])) {
|
|
110
|
+
resultText.push(arrayToList(renderList[key]))
|
|
111
|
+
} else {
|
|
112
|
+
resultText.push(`<p>${renderList[key]}</p>`)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return resultText.join('\n')
|
|
116
|
+
}
|
|
2
117
|
|
|
3
118
|
export function additionalHelper() {
|
|
4
119
|
return 'これは追加ヘルパーによって出力されているメッセージです。'
|
package/src-sample/js/editor.js
CHANGED
|
@@ -3,8 +3,15 @@ const sleep = waitTime => new Promise( resolve => setTimeout(resolve, waitTime)
|
|
|
3
3
|
const fetchData = (target) => {
|
|
4
4
|
return fetch(`/get_editor_target?md=${target}`)
|
|
5
5
|
.then(async res => {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
if (!res.ok) {
|
|
7
|
+
document.querySelector('#inputFileName').value = target
|
|
8
|
+
document.querySelector('#editorTextArea').value = `${target.split('.')[0]}についての記事を作成しましょう`
|
|
9
|
+
// submit('/preview', form)
|
|
10
|
+
throw new Error(`${target} does not exist.`)
|
|
11
|
+
} else {
|
|
12
|
+
const json = await res.json()
|
|
13
|
+
return json
|
|
14
|
+
}
|
|
8
15
|
})
|
|
9
16
|
}
|
|
10
17
|
const onloadFunction = async (e) => {
|
|
@@ -22,6 +29,9 @@ const onloadFunction = async (e) => {
|
|
|
22
29
|
inputFileName.value = json.filename
|
|
23
30
|
inputFileName.setAttribute('disabled', true)
|
|
24
31
|
submit('/preview', form)
|
|
32
|
+
}).catch(e => {
|
|
33
|
+
console.log('error!!!')
|
|
34
|
+
console.log(e)
|
|
25
35
|
})
|
|
26
36
|
}
|
|
27
37
|
select.addEventListener('change', async (event) => {
|
|
@@ -51,7 +61,7 @@ const onloadFunction = async (e) => {
|
|
|
51
61
|
formData.forEach((v, k) => {
|
|
52
62
|
obj[k] = v
|
|
53
63
|
})
|
|
54
|
-
fetch(fetchUrl, {
|
|
64
|
+
return fetch(fetchUrl, {
|
|
55
65
|
method: 'post',
|
|
56
66
|
body: JSON.stringify(obj)
|
|
57
67
|
}).then(async response => {
|
|
@@ -92,15 +102,19 @@ const sidebarToggle = (e) => {
|
|
|
92
102
|
toggle.addEventListener('click', (e) => {
|
|
93
103
|
e.preventDefault()
|
|
94
104
|
main.classList.toggle('sidebar-close')
|
|
105
|
+
localStorage.setItem('sidebar-is-open', !main.classList.contains('sidebar-close'))
|
|
95
106
|
})
|
|
107
|
+
if (localStorage.getItem('sidebar-is-open') === 'true') {
|
|
108
|
+
main.classList.remove('sidebar-close')
|
|
109
|
+
} else {
|
|
110
|
+
main.classList.add('sidebar-close')
|
|
111
|
+
}
|
|
96
112
|
const hamburger = document.querySelector('.hamburger-menu input[type="checkbox"]')
|
|
97
|
-
console.log(hamburger)
|
|
98
113
|
hamburger.addEventListener('change', (e) => {
|
|
99
114
|
main.classList.toggle('sidebar-close')
|
|
100
115
|
})
|
|
101
116
|
}
|
|
102
117
|
document.addEventListener('DOMContentLoaded', (event) => {
|
|
103
|
-
console.log(event)
|
|
104
118
|
onloadFunction(event)
|
|
105
119
|
sidebarToggle(event)
|
|
106
120
|
})
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
document.addEventListener('DOMContentLoaded', (e) => {
|
|
2
|
+
})
|
|
3
|
+
const url = new URL(location)
|
|
4
|
+
if (url.pathname !== '/editor') {
|
|
5
|
+
const link = document.querySelector('.editor_link')
|
|
6
|
+
link.href = `/editor?md=${url.pathname.replace('/', '')}.md`
|
|
7
|
+
link.innerHTML = `${url.pathname.replace('/', '')}のページを作成する`
|
|
8
|
+
}
|
|
@@ -17,7 +17,11 @@ export const get = async (req, res) => {
|
|
|
17
17
|
}
|
|
18
18
|
const file = `${pageDir}/${target}`
|
|
19
19
|
if (!fs.existsSync(`${file}`)) {
|
|
20
|
-
return
|
|
20
|
+
return {
|
|
21
|
+
status: 404,
|
|
22
|
+
contentType: 'application/json',
|
|
23
|
+
body: JSON.stringify({ content: '', filename: target })
|
|
24
|
+
}
|
|
21
25
|
}
|
|
22
26
|
const f = fs.readFileSync(`${file}`, 'utf8')
|
|
23
27
|
return {
|
|
@@ -16,6 +16,12 @@ export const post = async (req, res) => {
|
|
|
16
16
|
.on('end', async () => {
|
|
17
17
|
const json = JSON.parse(chunks.join())
|
|
18
18
|
const filename = json.inputFileName ? json.inputFileName : json.selectDataFile
|
|
19
|
+
if (!filename) {
|
|
20
|
+
res.writeHead(400, { 'content-type': 'application/json' })
|
|
21
|
+
return res.end(JSON.stringify({
|
|
22
|
+
message: 'filename is requried.'
|
|
23
|
+
}))
|
|
24
|
+
}
|
|
19
25
|
const pageData = makePageData(filename, json.content)
|
|
20
26
|
const rendered = await render(pageData.template, pageData)
|
|
21
27
|
res.writeHead(200, { 'content-type': 'application/json' })
|
|
@@ -48,10 +48,13 @@
|
|
|
48
48
|
</main>
|
|
49
49
|
{if isEditorEnabled() }
|
|
50
50
|
<div class="container">
|
|
51
|
-
<a href="/editor?md={{name}}.{{__filetype}}">編集する</a>
|
|
51
|
+
<a href="/editor?md={{name}}.{{__filetype}}" class="editor_link">編集する</a>
|
|
52
52
|
</div>
|
|
53
53
|
{/if}
|
|
54
54
|
|
|
55
55
|
{include('template/footer.html')}
|
|
56
|
+
{if add_script}
|
|
57
|
+
<script src="{{ADD_SCRIPT}}" async></script>
|
|
58
|
+
{/if}
|
|
56
59
|
</body>
|
|
57
60
|
</html>
|
|
@@ -4,22 +4,12 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>{{SITE_NAME}}</title>
|
|
7
|
-
{
|
|
8
|
-
<link rel="stylesheet" href="${/css/editor.css<<editor.css}">
|
|
7
|
+
<link rel="stylesheet" href="${/css/editor.css<<reset.css,editor.css}">
|
|
9
8
|
<script src="/js/editor.js" defer></script>
|
|
10
9
|
|
|
11
10
|
</head>
|
|
12
11
|
<body>
|
|
13
|
-
<
|
|
14
|
-
<p class="container">
|
|
15
|
-
<a href="/">{{SITE_NAME}}/Editor</a>
|
|
16
|
-
</p>
|
|
17
|
-
<div class="hamburger-menu">
|
|
18
|
-
<input type="checkbox" id="menu-btn-check">
|
|
19
|
-
<label for="menu-btn-check" class="menu-btn"><span></span></label>
|
|
20
|
-
</div>
|
|
21
|
-
</header>
|
|
22
|
-
<main class="container sidebar-close">
|
|
12
|
+
<main class="container">
|
|
23
13
|
<div class="sidebar">
|
|
24
14
|
<ul>
|
|
25
15
|
<script type="ssg">
|
|
@@ -31,32 +21,38 @@
|
|
|
31
21
|
<div class="sidebar-toggle"> </div>
|
|
32
22
|
</div>
|
|
33
23
|
<form action="/editor" class="editor" method="post" id="editor">
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
<div class="editor-options">
|
|
25
|
+
<div>
|
|
26
|
+
<input id="inputFileName" name="inputFileName" type="text" value="" placeholder="sample.md">
|
|
27
|
+
<select id="selectDataFile" name="selectDataFile">
|
|
28
|
+
<option value="">新規作成</option>
|
|
29
|
+
<script type="ssg">
|
|
30
|
+
return helper.readIndex().map(p => {
|
|
39
31
|
return `<option value="${p.name}.${p.__filetype}">${p.url}.${p.__filetype}</option>`
|
|
40
32
|
}).join("\n")
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
</script>
|
|
34
|
+
</select>
|
|
35
|
+
</div>
|
|
36
|
+
<div>
|
|
37
|
+
<input type="submit" value="preview" data-url="/preview">
|
|
38
|
+
<input type="submit" value="save" data-url="/editor">
|
|
39
|
+
<a href="/">戻る</a>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
43
42
|
<div class="textareaAndPreview">
|
|
44
43
|
<textarea id="editorTextArea" name="content" cols="30" rows="10">
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
ここにマークダウンを入力してください。
|
|
44
|
+
{{ MARKDOWN_NOT_PARSED }}
|
|
48
45
|
</textarea>
|
|
49
46
|
<div class="preview">
|
|
50
47
|
<div id="previewContent"></div>
|
|
51
48
|
</div>
|
|
52
49
|
</div>
|
|
53
50
|
<input type="hidden" name="token" value="{{TOKEN}}">
|
|
54
|
-
<div>
|
|
55
|
-
<input type="submit" value="preview" data-url="/preview">
|
|
56
|
-
<input type="submit" value="save" data-url="/editor">
|
|
57
|
-
<a href="/">戻る</a>
|
|
58
|
-
</div>
|
|
59
51
|
</form>
|
|
52
|
+
<div class="hamburger-menu">
|
|
53
|
+
<input type="checkbox" id="menu-btn-check">
|
|
54
|
+
<label for="menu-btn-check" class="menu-btn"><span></span></label>
|
|
55
|
+
</div>
|
|
60
56
|
</main>
|
|
61
57
|
</body>
|
|
62
58
|
</html>
|
package/helper/index.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { allData } from "../lib/indexer.js";
|
|
2
|
-
import { replaceVariablesFilter } from "../lib/filter.js";
|
|
3
|
-
import config from '../lib/config.js'
|
|
4
|
-
|
|
5
|
-
export function readIndex (filter = null) {
|
|
6
|
-
const data = Object.entries(allData)
|
|
7
|
-
.sort((a, b) => new Date(b[1].published) - new Date(a[1].published))
|
|
8
|
-
return filter
|
|
9
|
-
? data.filter(v => v[0].indexOf(filter) === 0).map(v => v[1])
|
|
10
|
-
: data.map(v => v[1])
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function dateFormat(dateString) {
|
|
14
|
-
const date = new Date(dateString)
|
|
15
|
-
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function render(text, variables) {
|
|
19
|
-
return replaceVariablesFilter(text, variables)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function getPageData(name) {
|
|
23
|
-
return allData[name]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let indexedItemsSorted = null
|
|
27
|
-
export function indexedItems() {
|
|
28
|
-
if (indexedItemsSorted) {
|
|
29
|
-
return indexedItemsSorted
|
|
30
|
-
}
|
|
31
|
-
const sorted = readIndex()
|
|
32
|
-
.filter(v => v.index && v.published != '1970-01-01')
|
|
33
|
-
.sort((a, b) => new Date(a.published) - new Date(b.published))
|
|
34
|
-
let prev, next
|
|
35
|
-
for (const item of sorted) {
|
|
36
|
-
if (prev) {
|
|
37
|
-
prev.next = {
|
|
38
|
-
name: item.name,
|
|
39
|
-
published: item.published,
|
|
40
|
-
url: item.url,
|
|
41
|
-
title: item.title,
|
|
42
|
-
}
|
|
43
|
-
item.prev = {
|
|
44
|
-
name: prev.name,
|
|
45
|
-
published: prev.published,
|
|
46
|
-
url: prev.url,
|
|
47
|
-
title: prev.title,
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
prev = item
|
|
51
|
-
}
|
|
52
|
-
indexedItemsSorted = sorted
|
|
53
|
-
return indexedItemsSorted
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* 配列を再帰的に順不同リストに変換する
|
|
58
|
-
* @param {Array|string} arrayOrText
|
|
59
|
-
* @returns {mixed}
|
|
60
|
-
*/
|
|
61
|
-
export function arrayToList(arrayOrText) {
|
|
62
|
-
if (typeof arrayOrText === 'string') {
|
|
63
|
-
return `<li>${arrayOrText}</li>`
|
|
64
|
-
}
|
|
65
|
-
if (Array.isArray(arrayOrText)) {
|
|
66
|
-
let resultListText = '<ul>'
|
|
67
|
-
for (const item of arrayOrText) {
|
|
68
|
-
if (Array.isArray(item)) {
|
|
69
|
-
resultListText += `<li>${arrayToList(item)}</li>`
|
|
70
|
-
} else {
|
|
71
|
-
resultListText += `<li>${item}</li>`
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
resultListText += '</ul>'
|
|
75
|
-
arrayOrText = resultListText
|
|
76
|
-
}
|
|
77
|
-
return arrayOrText
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function renderIndex(pages, nodate = 'nodate', headingTag = 'h3') {
|
|
81
|
-
if (!pages) {
|
|
82
|
-
pages = readIndex()
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const renderList = {}
|
|
86
|
-
for (const page of pages) {
|
|
87
|
-
if (page.index) {
|
|
88
|
-
const url = config.relative_path ? config.relative_path + page.url : page.url
|
|
89
|
-
if (page.published === '1970-01-01') {
|
|
90
|
-
if (!renderList[nodate]) {
|
|
91
|
-
renderList[nodate] = []
|
|
92
|
-
}
|
|
93
|
-
renderList[nodate].push(`<a href="${url}">${page.title}</a>`)
|
|
94
|
-
continue
|
|
95
|
-
}
|
|
96
|
-
const published = new Date(page.published)
|
|
97
|
-
const year = `${published.getFullYear()}年`
|
|
98
|
-
const date = `${published.getMonth() +1}月${published.getDate()}日`
|
|
99
|
-
if (!renderList[year]) {
|
|
100
|
-
renderList[year] = []
|
|
101
|
-
}
|
|
102
|
-
renderList[year].push(`<a href="${url}">${page.title}</a> (${date})`)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const resultText = []
|
|
107
|
-
for (const key in renderList) {
|
|
108
|
-
resultText.push(`<${headingTag}>${key}</${headingTag}>`)
|
|
109
|
-
if (Array.isArray(renderList[key])) {
|
|
110
|
-
resultText.push(arrayToList(renderList[key]))
|
|
111
|
-
} else {
|
|
112
|
-
resultText.push(`<p>${renderList[key]}</p>`)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return resultText.join('\n')
|
|
116
|
-
}
|