Skip to content

Commit 7117633

Browse files
committed
rewrite with JavaScript Plugins
1 parent 5328b7c commit 7117633

File tree

11 files changed

+441
-356
lines changed

11 files changed

+441
-356
lines changed

deno.jsonc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"useTabs": false,
1313
"lineWidth": 80,
1414
"include": [
15-
"src/util/**/*.js",
15+
"src/**/*.js",
1616
"main.js",
1717
"public/JavaScript/*.js",
1818
"scripts/*.ts",

main.js

Lines changed: 35 additions & 278 deletions
Original file line numberDiff line numberDiff line change
@@ -1,291 +1,48 @@
1-
import { markdown } from './src/util/remark/markdown.js'
2-
import {
3-
compileCss,
4-
convertToUSA,
5-
generateSingleFile,
6-
handleUTC,
7-
parseYaml,
8-
replaceBody,
9-
replaceHead,
10-
startServer,
11-
} from './src/util/utils.js'
12-
import {
13-
getRss,
14-
giscus,
15-
templateArticle,
16-
templateBox,
17-
templateProcess,
18-
} from './src/util/template.js'
19-
import { copy, ensureDir, ensureFile, exists, existsSync } from 'fs'
1+
import { assertPlugin } from './src/plugins/asserts.js'
2+
import { Core } from './src/plugins/core.js'
3+
import { feedPlugin } from './src/plugins/feed.js'
4+
import { pagesPlugin } from './src/plugins/pages.js'
5+
import { postPlugin } from './src/plugins/posts.js'
6+
import { existsSync } from 'fs'
7+
import { startServer } from './src/util/utils.js'
208
import 'https://deno.land/[email protected]/dotenv/load.ts'
219

22-
/**
23-
* @typedef {Object} MetaData
24-
* @property {string} MetaData.date
25-
* @property {string} MetaData.title
26-
* @property {string} MetaData.summary
27-
* @property {string[]} MetaData.tags
28-
*/
29-
30-
/**@type {MetaData[]}*/
31-
const metaData = []
32-
const dist = import.meta.resolve('./dist/')
33-
const src = import.meta.resolve('./src/')
34-
const randomNumber = Math.floor(Math.random() * 1000000)
35-
36-
// global config
37-
const WEBSITE = Deno.env.get('WEBSITE')
38-
const author = Deno.env.get('AUTHOR')
39-
const port = Deno.env.get('PORT')
40-
const header = await Deno.readTextFile(new URL('./util/header.html', src))
41-
const footer = await Deno.readTextFile(new URL('./util/footer.html', src))
42-
43-
const getPosts = (title, content, isPosts = false) =>
44-
`${templateArticle({ title, content, giscus: isPosts ? giscus : '' })}`
45-
46-
const getTags = (title, tags) =>
47-
tags.reduce(
48-
(acc, tag) =>
49-
acc + `<a class="tag" href="/./${title}/${tag}/">
50-
<i class="fa-solid fa-tag"></i> ${tag}
51-
</a>`,
52-
'',
53-
)
54-
55-
/**
56-
* @param {string} title
57-
* @param {MetaData[]} iters
58-
*/
59-
function getArchive(title, iters) {
60-
const content = iters.reduce(
61-
(acc, { date, summary }) => {
62-
const place = `/./posts/${handleUTC(date)}/`
63-
return acc +
64-
`<p><a class="decoration-line" href=${place} target="_blank"> ${summary} ··· ${convertToUSA(date)
65-
}</a></p>`
66-
},
67-
'',
68-
)
69-
70-
return templateArticle({ title, content })
71-
}
72-
/**
73-
* @param {Map<string,MetaData[]>} map
74-
* @param {string} url
75-
* @param {string} dest
76-
*/
77-
async function completeTask(map, url, dest) {
78-
for (const k of map.keys()) {
79-
const tagsUrl = new URL(`./${k}/index.html`, url)
80-
const task = await generatePage(tagsUrl, k, `${author} ~ ${k}`, k)
81-
await task(getArchive, map.get(k))
10+
async function createConfig() {
11+
const baseConfig = {
12+
dist: import.meta.resolve('./dist/'),
13+
src: import.meta.resolve('./src/'),
14+
website: Deno.env.get('WEBSITE'),
15+
author: Deno.env.get('AUTHOR'),
16+
port: Deno.env.get('PORT'),
17+
version: Math.floor(Math.random() * 1000000),
8218
}
8319

84-
const task = await generatePage(
85-
new URL('./index.html', url),
86-
[...map.keys()].join(', '),
87-
`${author} ~ ${dest}`,
88-
dest,
20+
const header = await Deno.readTextFile(
21+
new URL('./util/header.html', baseConfig.src),
22+
)
23+
const footer = await Deno.readTextFile(
24+
new URL('./util/footer.html', baseConfig.src),
8925
)
90-
await task(getPosts, getTags(dest, [...map.keys()]))
91-
}
92-
93-
async function generatePage(
94-
/**@type {string}*/ dist,
95-
/**@type {string}*/ keywords,
96-
/**@type {string}*/ description,
97-
/**@type {string}*/ title,
98-
) {
99-
if (!await exists(dist)) await ensureFile(dist)
100-
const head = await replaceHead(keywords, description, title, randomNumber)
101-
102-
return async (fn, ...params) => {
103-
const content = fn(title, ...params)
104-
const index = `${head}${header}${content}${footer}`
105-
106-
await Deno.writeTextFile(dist, index)
107-
}
108-
}
109-
110-
// Handle the meta data
111-
async function handlePosts() {
112-
const posts = import.meta.resolve('./src/posts/')
113-
const iter = Deno.readDir(new URL(posts))[Symbol.asyncIterator]()
114-
while (true) {
115-
const { value, done } = await iter.next()
116-
if (done) break
117-
const file = await Deno.readTextFile(new URL(value.name, posts))
118-
const [{ date, title, summary, tags }, md] = parseYaml(file)
119-
120-
// Handle the posts
121-
{
122-
const timeDir = new URL(`./posts/${handleUTC(date)}/index.html`, dist)
123-
const task = await generatePage(timeDir, tags.join(', '), summary, title)
124-
await task(getPosts, await markdown(md), true)
125-
}
126-
127-
metaData.push({ date, title, summary, tags })
128-
}
129-
metaData.sort((a, b) => new Date(b.date) - new Date(a.date))
130-
}
131-
132-
// Handle the others source
133-
async function Others() {
134-
await ensureDir(new URL('./public/', dist))
135-
for await (const entry of Deno.readDir(new URL('../public/', src))) {
136-
if (entry.name === 'css') continue
137-
const __src_p = new URL(`../public/${entry.name}`, src)
138-
const __dist_p = new URL(`./public/${entry.name}`, dist)
139-
if (entry.name === 'JavaScript') {
140-
await ensureFile(
141-
new URL(`./${entry.name}/index.${randomNumber}.js`, __dist_p),
142-
)
143-
await copy(
144-
new URL(`./${entry.name}/index.js`, __src_p),
145-
new URL(`./${entry.name}/index.${randomNumber}.js`, __dist_p),
146-
{ overwrite: true },
147-
)
148-
continue
149-
}
150-
await copy(__src_p, __dist_p, { overwrite: true })
151-
}
152-
153-
// compile the css
154-
const __css_d = new URL('./public/css/', dist)
155-
await ensureDir(__css_d)
156-
for await (const entry of Deno.readDir(new URL('../public/css/', src))) {
157-
const path = new URL(`../public/css/${entry.name}`, src)
158-
const code = await compileCss(path)
159-
const fileName = entry.name.split('.').join(`.${randomNumber}.`)
160-
await Deno.writeFile(new URL(fileName, __css_d), code)
161-
}
162-
163-
// Handle the CNAME
164-
const cname = new URL('./CNAME', dist)
165-
166-
// Handle the RSS
167-
const rss = new URL('./feed.xml', dist)
168-
const itemsRss = metaData.reduce((acc, { date, title, summary }) => {
169-
const url = `${WEBSITE}posts/${handleUTC(date)}/`
170-
return acc + `<item>
171-
<title>${title}</title>
172-
<link>${url}</link>
173-
<description>${summary}</description>
174-
<pubDate>${new Date(date).toUTCString()}</pubDate>
175-
</item>`
176-
}, '')
177-
178-
// sitemap
179-
const sitemap = new URL('./sitemap.xml', dist)
180-
const itemsSitemap = `<?xml version="1.0" encoding="UTF-8"?>
181-
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
182-
${metaData.reduce((acc, { date }) =>
183-
`${acc}<url><loc>${WEBSITE}posts/${handleUTC(date)}/</loc></url>`, '')
184-
}
185-
</urlset>`
186-
187-
// robots
188-
const robots = new URL('./robots.txt', dist)
189-
const robotsContent = `User-agent: *
190-
Allow: /
191-
Sitemap: ${WEBSITE}sitemap.xml`
192-
193-
const files = [
194-
[rss, getRss(author, WEBSITE, itemsRss)],
195-
[sitemap, itemsSitemap],
196-
[robots, robotsContent],
197-
]
198-
const g = generateSingleFile(cname, WEBSITE.slice(8, -1))
199-
g.next()
200-
files.forEach((file) => g.next(file))
201-
}
202-
203-
// Home page
204-
async function Home() {
205-
const homeDest = new URL('./home/', dist)
206-
let indexPage = await Deno.readTextFile(new URL('../index.html', src))
207-
indexPage = replaceBody(indexPage, header, footer, randomNumber)
208-
209-
const mLength = metaData.length
210-
const lastPage = Math.ceil(mLength / 8)
211-
let content = ''
212-
213-
for (let index = 0; index < mLength; index++) {
214-
const { date, title, summary, tags } = metaData[index]
215-
const aTags = getTags('tags', tags)
216-
content += templateBox({
217-
place: `/./posts/${handleUTC(date)}/`,
218-
title,
219-
summary,
220-
time: convertToUSA(date),
221-
tags: aTags,
222-
})
223-
224-
if ((index + 1) % 8 === 0 || index + 1 === mLength) {
225-
const cur = index + 1 === mLength ? lastPage : Math.floor((index + 1) / 8)
226-
const process = templateProcess({
227-
before: cur > 2 ? `/./home/${cur - 1}/` : '/',
228-
page: `${cur} / ${lastPage}`,
229-
after: index === mLength ? '#' : `/./home/${cur + 1}/`,
230-
})
231-
const home = indexPage.replace('<!-- Template -->', content + process)
232-
233-
// Reset the content
234-
content = ''
235-
236-
// Generate the home dir
237-
if (cur !== 1) await ensureDir(new URL(`${cur}/`, homeDest))
238-
const url = cur === 1
239-
? new URL('./index.html', dist)
240-
: new URL(`${cur}/index.html`, homeDest)
241-
242-
await Deno.writeTextFile(url, home)
243-
}
244-
}
245-
}
246-
247-
// Archive page
248-
async function Archive() {
249-
const archiveDest = new URL('./archive/', dist)
250-
const map = new Map()
251-
for (const meta of metaData) {
252-
const year = new Date(meta.date).getFullYear()
253-
map.has(year) ? map.get(year).push(meta) : map.set(year, [meta])
254-
}
255-
await completeTask(map, archiveDest, 'archive')
256-
}
25726

258-
// Tags page
259-
async function Tags() {
260-
const tagsDest = new URL('./tags/', dist)
261-
const map = new Map()
262-
for (const meta of metaData) {
263-
meta.tags.forEach((tag) => {
264-
map.has(tag) ? map.get(tag).push(meta) : map.set(tag, [meta])
265-
})
27+
return {
28+
...baseConfig,
29+
header,
30+
footer,
26631
}
267-
await completeTask(map, tagsDest, 'tags')
268-
}
269-
270-
async function About() {
271-
const __dist_about = new URL('./about/index.html', dist)
272-
if (!await exists(__dist_about)) await ensureFile(__dist_about)
273-
const __src_about = new URL('./about/about.html', src)
274-
275-
const about = (await Deno.readTextFile(__src_about))
276-
.replace('<!-- base.css -->', `/public/css/base.${randomNumber}.css`)
277-
.replace('<!-- index.css -->', `/public/css/index.${randomNumber}.css`)
278-
.replace('<!-- index.js -->', `/public/JavaScript/index.${randomNumber}.js`)
279-
280-
await Deno.writeTextFile(__dist_about, about)
28132
}
28233

34+
const config = await createConfig()
28335
async function main() {
284-
if (existsSync(new URL(dist))) {
285-
Deno.removeSync(new URL(dist), { recursive: true })
36+
if (existsSync(new URL(config.dist))) {
37+
Deno.removeSync(new URL(config.dist), { recursive: true })
28638
}
287-
await handlePosts()
288-
Promise.all([Home(), Archive(), Tags(), Others(), About()])
39+
const core = new Core()
40+
core.use(postPlugin)
41+
core.use(assertPlugin)
42+
core.use(feedPlugin)
43+
core.use(pagesPlugin)
44+
await core.runHook('beforeBuild', config)
45+
await core.runHook('afterBuild', config)
28946
}
29047

29148
// Handle the http server
@@ -295,5 +52,5 @@ if (mode === 'DEV' || mode === 'PRO') {
29552
}
29653

29754
if (mode === 'DEV' || mode === 'PRE') {
298-
startServer(port)
55+
startServer(config.port)
29956
}

public/JavaScript/index.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ document.addEventListener('DOMContentLoaded', () => {
8080
document.startViewTransition(
8181
() => toggleColor(darkMode === 'dark', darkIcon),
8282
)
83-
;[
84-
['--click-x', `${x}px`],
85-
['--click-y', `${y}px`],
86-
['--end-radius', `${endRadius}px`]
87-
].forEach(([v, c]) => document.documentElement.style.setProperty(v, c))
83+
;[
84+
['--click-x', `${x}px`],
85+
['--click-y', `${y}px`],
86+
['--end-radius', `${endRadius}px`],
87+
].forEach(([v, c]) => document.documentElement.style.setProperty(v, c))
8888
})
8989

9090
const header = document.querySelector('header')

0 commit comments

Comments
 (0)