move to vue-blogify
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
> 1%
|
||||||
|
last 2 versions
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
public/posts/* linguist-vendored
|
||||||
@@ -1,125 +1,21 @@
|
|||||||
|
|
||||||
# Created by https://www.gitignore.io/api/node,macos
|
|
||||||
# Edit at https://www.gitignore.io/?templates=node,macos
|
|
||||||
|
|
||||||
### macOS ###
|
|
||||||
# General
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.AppleDouble
|
node_modules
|
||||||
.LSOverride
|
/dist
|
||||||
|
|
||||||
# Icon must end with two \r
|
# local env files
|
||||||
Icon
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
# Thumbnails
|
# Log files
|
||||||
._*
|
|
||||||
|
|
||||||
# Files that might appear in the root of a volume
|
|
||||||
.DocumentRevisions-V100
|
|
||||||
.fseventsd
|
|
||||||
.Spotlight-V100
|
|
||||||
.TemporaryItems
|
|
||||||
.Trashes
|
|
||||||
.VolumeIcon.icns
|
|
||||||
.com.apple.timemachine.donotpresent
|
|
||||||
|
|
||||||
# Directories potentially created on remote AFP share
|
|
||||||
.AppleDB
|
|
||||||
.AppleDesktop
|
|
||||||
Network Trash Folder
|
|
||||||
Temporary Items
|
|
||||||
.apdisk
|
|
||||||
|
|
||||||
### Node ###
|
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Editor directories and files
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
.idea
|
||||||
|
.vscode
|
||||||
# Runtime data
|
*.suo
|
||||||
pids
|
*.ntvs*
|
||||||
*.pid
|
*.njsproj
|
||||||
*.seed
|
*.sln
|
||||||
*.pid.lock
|
*.sw?
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# TypeScript v1 declaration files
|
|
||||||
typings/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variables file
|
|
||||||
.env
|
|
||||||
.env.test
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# next.js build output
|
|
||||||
.next
|
|
||||||
|
|
||||||
# nuxt.js build output
|
|
||||||
.nuxt
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# End of https://www.gitignore.io/api/node,macos
|
|
||||||
|
|
||||||
/dist/
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
[submodule "plugins/cogear-plugin-blog"]
|
|
||||||
path = plugins/cogear-plugin-blog
|
|
||||||
url = https://github.com/patarapolw/cogear-plugin-blog.git
|
|
||||||
[submodule "plugins/cogear-plugin-base-url"]
|
|
||||||
path = plugins/cogear-plugin-base-url
|
|
||||||
url = https://github.com/patarapolw/cogear-plugin-base-url.git
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Pacharapol Withayasakpunt
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1 +1,28 @@
|
|||||||
Clone using `git clone --recursive git@repo.org:your_repo.git`.
|
# Vue Blogify
|
||||||
|
|
||||||
|
Vue CLI-based static blogging platform
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
- Edit `config.yaml`
|
||||||
|
- Edit layouts (using `*.vue`) in `src/layouts/`
|
||||||
|
- Add posts in `public/posts`, preferrably in `public/posts/<YEAR>/<MONTH>`. HTML, Pug and Markdown are supported.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
- I use NPM, and Vue CLI 3, so `npm install`
|
||||||
|
- Run using `npm run dev`
|
||||||
|
|
||||||
|
## Building and deploying
|
||||||
|
|
||||||
|
- Build using `npm run build`
|
||||||
|
- Deploy as static website, maybe using [gh-pages](https://www.npmjs.com/package/gh-pages).
|
||||||
|
- To deploy to most static websites, set `publicPath` in `vue.config.js` to `/`.
|
||||||
|
- For non-user GitHub Pages, set `publicPath` to `/<REPO_NAME>`.
|
||||||
|
- For Cordova, Electron, or local, set `publicPath` to `""`.
|
||||||
|
- Note that, if `publicPath` is not `/`, [Vue router's History Mode](https://router.vuejs.org/guide/essentials/history-mode.html) might not work.
|
||||||
|
- For instructions, see <https://cli.vuejs.org/guide/deployment.html>
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
See <https://vue-blogify.patarapolw.now.sh>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@vue/app",
|
||||||
|
{
|
||||||
|
"useBuiltIns": "entry"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,24 +1,19 @@
|
|||||||
title: 中文 Diary
|
title: 中文 Diary
|
||||||
description:
|
tabs:
|
||||||
keywords:
|
- name: 千字文
|
||||||
theme: blog
|
to: /tag/千字文
|
||||||
baseUrl: /
|
- name: 句子
|
||||||
blog:
|
to: /tag/句子
|
||||||
index: "" # Provide posts to index page
|
- name: 分类词汇
|
||||||
regex: "^p/"
|
to: /tag/分类词汇
|
||||||
tagUri: 'tag'
|
posts:
|
||||||
perPage: 5
|
perPage: 5
|
||||||
split: ===
|
|
||||||
title: "中文 Diary"
|
|
||||||
tags:
|
|
||||||
- 千字文
|
|
||||||
- 句子
|
|
||||||
- 分类词汇
|
|
||||||
pages:
|
|
||||||
^/?p/:
|
|
||||||
layout: post
|
|
||||||
author:
|
author:
|
||||||
login: polvcode
|
login: polvcode
|
||||||
avatar: 'https://en.gravatar.com/userimage/35152960/7140205ee2a71cbe54d3f2ac43c0370d.jpg?size=24'
|
avatar: 'https://en.gravatar.com/userimage/35152960/7140205ee2a71cbe54d3f2ac43c0370d.jpg?size=24'
|
||||||
link: https://polvcode.dev
|
link: https://polvcode.dev
|
||||||
output: dist/
|
about: true
|
||||||
|
external:
|
||||||
|
disqus: zhdiary
|
||||||
|
google:
|
||||||
|
analytics: UA-146246917-1
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
const ghPages = require("gh-pages");
|
|
||||||
const {spawnSync} = require("child_process");
|
|
||||||
const rimraf = require("rimraf");
|
|
||||||
|
|
||||||
rimraf.sync("node_modules/gh-pages/.cache")
|
|
||||||
|
|
||||||
spawnSync("cogear", ["build"], {
|
|
||||||
stdio: "inherit"
|
|
||||||
});
|
|
||||||
|
|
||||||
ghPages.publish("dist", {
|
|
||||||
branch: "master",
|
|
||||||
repo: "https://git.heroku.com/zhdiary.git"
|
|
||||||
}, (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Posted to https://zhdiary.herokuapp.com")
|
|
||||||
});
|
|
||||||
@@ -1,41 +1,56 @@
|
|||||||
{
|
{
|
||||||
"name": "zhdiary",
|
"name": "vue-blogify",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"description": "My journey through Chinese language",
|
"private": true,
|
||||||
"main": "server.js",
|
"types": "src/declaration.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vue-cli-service serve:async",
|
||||||
|
"build": "vue-cli-service build:async",
|
||||||
|
"test": "ts-mocha -p tsconfig.test.json src/**/*.spec.ts",
|
||||||
|
"deploy": "npm run build && gh-pages -d dist"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/jquery": "^3.3.31"
|
"@types/uuid": "^3.4.5",
|
||||||
|
"bootstrap-vue": "^2.0.0-rc.19",
|
||||||
|
"core-js": "^2.6.5",
|
||||||
|
"esm": "^3.2.25",
|
||||||
|
"fast-glob": "^3.0.4",
|
||||||
|
"gray-matter": "^4.0.2",
|
||||||
|
"hyperpug": "^0.1.7",
|
||||||
|
"hyperscript": "^2.0.2",
|
||||||
|
"js-yaml": "^3.13.1",
|
||||||
|
"moment": "^2.24.0",
|
||||||
|
"showdown": "^1.9.0",
|
||||||
|
"uuid": "^3.3.3",
|
||||||
|
"vue": "^2.6.10",
|
||||||
|
"vue-class-component": "^7.0.2",
|
||||||
|
"vue-disqus": "^3.0.5",
|
||||||
|
"vue-property-decorator": "^8.1.0",
|
||||||
|
"vue-router": "^3.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"gh-pages": "^2.1.1",
|
"@babel/polyfill": "^7.4.4",
|
||||||
"husky": "^3.0.3",
|
"@types/expect": "^1.20.4",
|
||||||
"hyperscript": "^2.0.2",
|
"@types/mocha": "^5.2.7",
|
||||||
"jstransformer-markdown-it": "^2.1.0",
|
"@vue/cli-plugin-babel": "^3.10.0",
|
||||||
"p-iteration": "^1.1.8",
|
"@vue/cli-plugin-typescript": "^3.10.0",
|
||||||
"pug": "^2.0.4",
|
"@vue/cli-service": "^3.10.0",
|
||||||
"showdown": "^1.9.0",
|
"bootstrap": "^4.3.1",
|
||||||
"webpack": "^4.39.1",
|
"mocha": "^6.2.0",
|
||||||
"webpack-merge": "^4.2.1"
|
"mutationobserver-shim": "^0.3.3",
|
||||||
|
"node-sass": "^4.12.0",
|
||||||
|
"popper.js": "^1.15.0",
|
||||||
|
"portal-vue": "^2.1.4",
|
||||||
|
"sass-loader": "^7.1.0",
|
||||||
|
"ts-mocha": "^6.0.0",
|
||||||
|
"typescript": "^3.4.3",
|
||||||
|
"vue-cli-plugin-bootstrap-vue": "^0.4.0",
|
||||||
|
"vue-cli-plugin-pug": "^1.0.7",
|
||||||
|
"vue-template-compiler": "^2.6.10"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"vuePlugins": {
|
||||||
"start": "cogear",
|
"service": [
|
||||||
"build": "cogear build",
|
"vue.async.config.js"
|
||||||
"deploy": "node deploy.js"
|
]
|
||||||
},
|
|
||||||
"author": {
|
|
||||||
"name": "Pacharapol Withayasakpunt",
|
|
||||||
"email": "patarapolw@gmail.com",
|
|
||||||
"url": "https://polvcode.dev"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/patarapolw/zhdiary.git"
|
|
||||||
},
|
|
||||||
"homepage": "https://zhdiary.herokuapp.com",
|
|
||||||
"husky": {},
|
|
||||||
"engines": {
|
|
||||||
"node": "10.16.0",
|
|
||||||
"npm": "6.10.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "custom-render",
|
|
||||||
"description": "Cogear.JS custom Webpack plugin.",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": "Pacharapol Withayasakpunt<patarapolw@gmail.com>",
|
|
||||||
"homepage": "https://github.com/patarapolw/custom-webpack",
|
|
||||||
"main": "./plugin.js"
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
const { Markdown } = require("./plugin");
|
|
||||||
|
|
||||||
const md = new Markdown();
|
|
||||||
console.log(md.md2html(`
|
|
||||||
a | b | c
|
|
||||||
d | e | f
|
|
||||||
`));
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
autoprefixer: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 440 B After Width: | Height: | Size: 440 B |
|
Before Width: | Height: | Size: 912 B After Width: | Height: | Size: 912 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="<%= BASE_URL %>apple-touch-icon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="<%= BASE_URL %>favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="<%= BASE_URL %>favicon-16x16.png">
|
||||||
|
<link rel="manifest" href="<%= BASE_URL %>site.webmanifest">
|
||||||
|
<link rel="stylesheet" href="<%= BASE_URL %>index.css">
|
||||||
|
<title>中文 Diary - Record my journey to Chinese language</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but vue-blogify doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: "千字文"
|
title: "千字文"
|
||||||
date: "2019-08-10"
|
date: "2019-08-10"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/1"
|
title: "千字文 - 1/1"
|
||||||
date: "2019-08-11"
|
date: "2019-08-11"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 天地玄黃,宇宙洪荒。
|
.w-100.mt-3
|
||||||
|
h3.text-center 天地玄黃,宇宙洪荒。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://upload.wikimedia.org/wikipedia/commons/a/ab/天-order.gif" height=100)
|
img(src="https://upload.wikimedia.org/wikipedia/commons/a/ab/天-order.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/33618.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/33618.gif" height=100)
|
||||||
figcaption.text-center huang1
|
figcaption.text-center huang1
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/2"
|
title: "千字文 - 1/2"
|
||||||
date: "2019-08-12"
|
date: "2019-08-12"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 日月盈昃,辰宿列張。
|
.w-100.mt-3
|
||||||
|
h3.text-center 日月盈昃,辰宿列張。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/26085.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/26085.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/24373.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/24373.gif" height=100)
|
||||||
figcaption.text-center zhang1
|
figcaption.text-center zhang1
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/3"
|
title: "千字文 - 1/3"
|
||||||
date: "2019-08-13"
|
date: "2019-08-13"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 寒來暑往,秋收冬藏。
|
.w-100.mt-3
|
||||||
|
h3.text-center 寒來暑往,秋收冬藏。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/23506.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/23506.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/34255.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/34255.gif" height=100)
|
||||||
figcaption.text-center cang2
|
figcaption.text-center cang2
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/4"
|
title: "千字文 - 1/4"
|
||||||
date: "2019-08-14"
|
date: "2019-08-14"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 閏餘成歲,律呂調陽。
|
.w-100.mt-3
|
||||||
|
h3.text-center 閏餘成歲,律呂調陽。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
.hanzi-img 閏
|
.hanzi-img 閏
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/38525.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/38525.gif" height=100)
|
||||||
figcaption.text-center yang2
|
figcaption.text-center yang2
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/5"
|
title: "千字文 - 1/5"
|
||||||
date: "2019-08-15"
|
date: "2019-08-15"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 雲騰致雨,露結為霜。
|
.w-100.mt-3
|
||||||
|
h3.text-center 雲騰致雨,露結為霜。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/38642.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/38642.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/38684.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/38684.gif" height=100)
|
||||||
figcaption.text-center shuang1
|
figcaption.text-center shuang1
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/6"
|
title: "千字文 - 1/6"
|
||||||
date: "2019-08-16"
|
date: "2019-08-16"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 金生麗水,玉出崑岡。
|
.w-100.mt-3
|
||||||
|
h3.text-center 金生麗水,玉出崑岡。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/37329.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/37329.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/23713.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/23713.gif" height=100)
|
||||||
figcaption.text-center gang1
|
figcaption.text-center gang1
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/7"
|
title: "千字文 - 1/7"
|
||||||
date: "2019-08-17"
|
date: "2019-08-17"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 劍號巨闕,珠稱夜光。
|
.w-100.mt-3
|
||||||
|
h3.text-center 劍號巨闕,珠稱夜光。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/21133.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/21133.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/20809.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/20809.gif" height=100)
|
||||||
figcaption.text-center guang1
|
figcaption.text-center guang1
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/8"
|
title: "千字文 - 1/8"
|
||||||
date: "2019-08-18"
|
date: "2019-08-18"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 果珍李柰,菜重芥薑。
|
.w-100.mt-3
|
||||||
|
h3.text-center 果珍李柰,菜重芥薑。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/26524.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/26524.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
.hanzi-img 薑
|
.hanzi-img 薑
|
||||||
figcaption.text-center jiang1
|
figcaption.text-center jiang1
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 1/9"
|
title: "千字文 - 1/9"
|
||||||
date: "2019-08-19"
|
date: "2019-08-19"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 海咸河淡,鱗潛羽翔。
|
.w-100.mt-3
|
||||||
|
h3.text-center 海咸河淡,鱗潛羽翔。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/28023.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/28023.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/32724.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/32724.gif" height=100)
|
||||||
figcaption.text-center xiang2
|
figcaption.text-center xiang2
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 2/1"
|
title: "千字文 - 2/1"
|
||||||
date: "2019-08-20"
|
date: "2019-08-20"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 龍師火帝,鳥官人皇。
|
.w-100.mt-3
|
||||||
|
h3.text-center 龍師火帝,鳥官人皇。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/40845.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/40845.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/30343.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/30343.gif" height=100)
|
||||||
figcaption.text-center huang1
|
figcaption.text-center huang1
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "千字文 - 2/2"
|
title: "千字文 - 2/2"
|
||||||
date: "2019-08-21"
|
date: "2019-08-21"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 汉字
|
- 汉字
|
||||||
---
|
---
|
||||||
|
|
||||||
.w-100.mt-3: h3.text-center 始制文字,乃服衣裳。
|
.w-100.mt-3
|
||||||
|
h3.text-center 始制文字,乃服衣裳。
|
||||||
.w-100
|
.w-100
|
||||||
figure.d-inline-block
|
figure.d-inline-block
|
||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/22987.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/22987.gif" height=100)
|
||||||
@@ -34,7 +35,7 @@ tags:
|
|||||||
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/35059.gif" height=100)
|
img(src="https://www.mdbg.net/chinese/rsc/img/stroke_anim/35059.gif" height=100)
|
||||||
figcaption.text-center chang2
|
figcaption.text-center chang2
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
.w-100.mt-3
|
.w-100.mt-3
|
||||||
:markdown
|
:markdown
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: "句子 1.1"
|
title: "句子 1.1"
|
||||||
date: "2019-08-16 1:00"
|
date: "2019-08-16 01:00"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 句子
|
- 句子
|
||||||
---
|
---
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: "句子 1.2"
|
title: "句子 1.2"
|
||||||
date: "2019-08-17 1:00"
|
date: "2019-08-17 01:00"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 句子
|
- 句子
|
||||||
---
|
---
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: "句子 1.3"
|
title: "句子 1.3"
|
||||||
date: "2019-08-17 2:00"
|
date: "2019-08-17 02:00"
|
||||||
tags:
|
tag:
|
||||||
- 千字文
|
- 千字文
|
||||||
- 句子
|
- 句子
|
||||||
---
|
---
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: "身体1"
|
title: "身体1"
|
||||||
date: "2019-08-18 1:00"
|
date: "2019-08-18 01:00"
|
||||||
tags:
|
tag:
|
||||||
- 分类词汇
|
- 分类词汇
|
||||||
- 身体
|
- 身体
|
||||||
---
|
---
|
||||||
@@ -15,7 +15,7 @@ tags:
|
|||||||
|
|
||||||
Highlight text and press "x" inside the presentation to speak.
|
Highlight text and press "x" inside the presentation to speak.
|
||||||
|
|
||||||
| ===
|
===
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
胳膊 | gēbo | arm
|
胳膊 | gēbo | arm
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
div
|
||||||
|
b-navbar(toggleable="lg" type="dark" variant="success")
|
||||||
|
b-navbar-brand(to="/") {{title}}
|
||||||
|
b-navbar-toggle(target="nav-collapse")
|
||||||
|
b-collapse#nav-collapse(is-nav)
|
||||||
|
b-navbar-nav
|
||||||
|
b-nav-item(v-for="t in tabs" :key="t.name" :to="t.to" :url="t.url") {{t.name}}
|
||||||
|
b-navbar-nav.ml-auto
|
||||||
|
b-nav-form(@submit.stop.prevent)
|
||||||
|
b-form-input.mr-sm-2(size="sm" placeholder="Type to search" style="min-width: 200px" v-model="g.q")
|
||||||
|
b-nav-item(to="/about") About
|
||||||
|
b-container.mt-3
|
||||||
|
b-row
|
||||||
|
b-col(sm=12 lg=8)
|
||||||
|
router-view
|
||||||
|
b-col(sm=12 lg=4)
|
||||||
|
sidebar
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component } from "vue-property-decorator";
|
||||||
|
import Sidebar from "@/layouts/Sidebar.vue";
|
||||||
|
import { g } from "@/shared";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {Sidebar}
|
||||||
|
})
|
||||||
|
export default class App extends Vue {
|
||||||
|
private title = g.config.title || "BLOG"
|
||||||
|
private tabs = g.config.tabs || []
|
||||||
|
private g = g;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import "./disqus";
|
|
||||||
import "./app.scss";
|
|
||||||
|
|
||||||
window.addEventListener("keydown", (ev) => {
|
|
||||||
if (ev.key === "s") {
|
|
||||||
const s = window.getSelection().toString();
|
|
||||||
if (s) {
|
|
||||||
speak(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.onload = () => {
|
|
||||||
for (const a of Array.from(document.getElementsByTagName("a"))) {
|
|
||||||
const href = a.href;
|
|
||||||
console.log(href);
|
|
||||||
const m = /^slide:github:([^/]+)\/([^/]+)\/(.+)$/.exec(href);
|
|
||||||
if (m) {
|
|
||||||
const url = new URL("https://reveal-md.herokuapp.com/");
|
|
||||||
url.searchParams.append("q", `https://raw.githubusercontent.com/${m[1]}/${m[2]}/master/src/resources/${m[3]}`);
|
|
||||||
a.href = url.href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function speak(s: string) {
|
|
||||||
const allVoices = speechSynthesis.getVoices();
|
|
||||||
let vs = allVoices.filter((v) => /zh[-_]cn/i.test(v.lang));
|
|
||||||
if (vs.length === 0) {
|
|
||||||
vs = allVoices.filter((v) => /zh/i.test(v.lang));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vs.length > 0) {
|
|
||||||
const u = new SpeechSynthesisUtterance(s);
|
|
||||||
u.lang = vs[0].lang;
|
|
||||||
u.rate = 0.8;
|
|
||||||
speechSynthesis.speak(u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
After Width: | Height: | Size: 6.7 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
declare const POSTS: Record<string, any>[];
|
||||||
|
declare const CONFIG: Record<string, any>;
|
||||||
|
declare const README: string;
|
||||||
|
|
||||||
|
declare module "@/plugins/render";
|
||||||
|
declare module 'vue-disqus';
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
|
|
||||||
* LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/
|
|
||||||
/*
|
|
||||||
var disqus_config = function () {
|
|
||||||
this.page.url = PAGE_URL; // Replace PAGE_URL with your page's canonical URL variable
|
|
||||||
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
(function() { // DON'T EDIT BELOW THIS LINE
|
|
||||||
var d = document, s = d.createElement('script');
|
|
||||||
s.src = 'https://zhdiary.disqus.com/embed.js';
|
|
||||||
s.setAttribute('data-timestamp', +new Date());
|
|
||||||
(d.head || d.body).appendChild(s);
|
|
||||||
})();
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
:markdown
|
||||||
|
### Sorry, but no post can be found.
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default Vue.extend({
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
b-card
|
||||||
|
header: h1 Write a post!
|
||||||
|
.post-content
|
||||||
|
p Go to <code>./public/posts</code> folder and create your first post, creating <code>first-post.md</code> file filled with the following content:
|
||||||
|
pre.
|
||||||
|
---
|
||||||
|
title: First post
|
||||||
|
tag:
|
||||||
|
- news
|
||||||
|
---
|
||||||
|
# This is my first post!
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default Vue.extend({
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
b-card.mb-3.post
|
||||||
|
.post-meta.mb-3
|
||||||
|
.float-right {{dateString}}
|
||||||
|
.post-meta-author
|
||||||
|
a(:href="author.link"): b-img(rounded="circle" :src="author.avatar")
|
||||||
|
a(:href="author.link") {{author.login}}
|
||||||
|
h2
|
||||||
|
b-link(v-if="isTeaser" :to="to") {{title}}
|
||||||
|
span(v-else="") {{title}}
|
||||||
|
div
|
||||||
|
div(v-if="isTeaser" v-html="teaser")
|
||||||
|
div(v-else="" v-html="content")
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component, Prop } from "vue-property-decorator";
|
||||||
|
import moment, { Moment } from "moment";
|
||||||
|
import matter from "gray-matter";
|
||||||
|
import HyperPug from "hyperpug";
|
||||||
|
import { pugFilters, md } from "@/plugins/render";
|
||||||
|
import { g } from '../shared';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class Post extends Vue {
|
||||||
|
@Prop() private filename!: string;
|
||||||
|
@Prop({default: false}) private isTeaser!: boolean;
|
||||||
|
|
||||||
|
private matter: any = {};
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
if (this.matter.data) {
|
||||||
|
return this.matter.data.title || ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
get moment(): Moment | null {
|
||||||
|
if (this.matter.data && this.matter.data.date) {
|
||||||
|
return moment(this.matter.data.date);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get dateString() {
|
||||||
|
return this.moment ? this.moment.format("ddd D MMMM YYYY") : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
get author() {
|
||||||
|
const author = (this.matter.data ? this.matter.data.author : null) || g.config.author;
|
||||||
|
if (!author) {
|
||||||
|
return {
|
||||||
|
link: "#",
|
||||||
|
avatar: "#",
|
||||||
|
login: "Anonymous"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
get url() {
|
||||||
|
return this.filename.replace(/^public\//, process.env.BASE_URL || "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
get to() {
|
||||||
|
const m = this.moment;
|
||||||
|
if (m) {
|
||||||
|
return `/p/${m.format("YYYY")}/${m.format("MM")}/${
|
||||||
|
this.filename
|
||||||
|
.replace(/^.*\//, "")
|
||||||
|
.replace(/\.[^.]+$/, "")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
get teaser() {
|
||||||
|
const { content } = this.matter;
|
||||||
|
const m = /^([^]+)\s+===\s+([^]+)$/.exec(content || "");
|
||||||
|
if (m) {
|
||||||
|
return this.parseContent(m[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.parseContent(content || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
get content() {
|
||||||
|
const { content } = this.matter;
|
||||||
|
const m = /^([^]+)\s+===\s+([^]+)$/.exec(content || "");
|
||||||
|
console.log(m)
|
||||||
|
if (m) {
|
||||||
|
return this.parseContent(m[1] + (m[2] || ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.parseContent(content || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async mounted() {
|
||||||
|
console.log(this.url);
|
||||||
|
this.matter = matter(await (await fetch(this.url)).text());
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseContent(s: string): string {
|
||||||
|
if (/\.pug$/.test(this.filename)) {
|
||||||
|
s = new HyperPug(pugFilters).parse(s);
|
||||||
|
} else if (/\.html?$/.test(this.filename)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return md.md2html(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
div
|
||||||
|
b-card.mb-3
|
||||||
|
:markdown
|
||||||
|
#### Record my journey to Chinese by [@polvcode](https://polvcode.dev)
|
||||||
|
|
||||||
|
Highlight text and press "s" to speak.
|
||||||
|
a.twitter-timeline(href="https://twitter.com/ChinesePol" data-height="600") Tweets by ChinesePol
|
||||||
|
b-card
|
||||||
|
h3 Tag cloud
|
||||||
|
span.mr-3(v-for="t in tags" :key="t.name" :class="t.class")
|
||||||
|
b-link(:to="'/tag/' + t.name") {{t.name}}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component } from "vue-property-decorator";
|
||||||
|
import { g } from '../shared';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class Sidebar extends Vue {
|
||||||
|
get tags() {
|
||||||
|
const tagList: Record<string, number> = {};
|
||||||
|
|
||||||
|
g.posts.forEach((p) => {
|
||||||
|
for (const t of p.tag || []) {
|
||||||
|
tagList[t] = (tagList[t] || 0) + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.keys(tagList).sort().map((t) => {
|
||||||
|
return {
|
||||||
|
name: t,
|
||||||
|
class: (() => {
|
||||||
|
const count = tagList[t];
|
||||||
|
if (count > 30) {
|
||||||
|
return "c30"
|
||||||
|
} else if (count > 20) {
|
||||||
|
return "c20"
|
||||||
|
} else if (count > 10) {
|
||||||
|
return "c10"
|
||||||
|
} else if (count > 5) {
|
||||||
|
return "c5"
|
||||||
|
} else if (count > 3) {
|
||||||
|
return "c3"
|
||||||
|
} else if (count > 1) {
|
||||||
|
return "c2"
|
||||||
|
}
|
||||||
|
return "c1"
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.c30 {
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c20 {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c10 {
|
||||||
|
font-size: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c5 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c2 {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c1 {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import '@babel/polyfill';
|
||||||
|
import 'mutationobserver-shim';
|
||||||
|
import Vue from 'vue';
|
||||||
|
import './plugins/bootstrap-vue';
|
||||||
|
import App from './App.vue';
|
||||||
|
import router from './router';
|
||||||
|
import VueDisqus from 'vue-disqus';
|
||||||
|
import "./plugins/gtag";
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
Vue.use(VueDisqus)
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app')
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
title: '中文 Diary - My Chinese learning diary'
|
|
||||||
---
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
import BootstrapVue from 'bootstrap-vue'
|
||||||
|
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||||
|
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
||||||
|
|
||||||
|
Vue.use(BootstrapVue)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { g } from "@/shared";
|
||||||
|
import { dotGetter } from './search';
|
||||||
|
|
||||||
|
declare const dataLayer: any[];
|
||||||
|
|
||||||
|
async function gAnalytics(id: string) {
|
||||||
|
var d = document, s = d.createElement('script');
|
||||||
|
s.src = `https://www.googletagmanager.com/gtag/js?id=${id}`;
|
||||||
|
|
||||||
|
s.setAttribute('data-timestamp', new Date().toISOString());
|
||||||
|
(d.head || d.body).appendChild(s);
|
||||||
|
|
||||||
|
(window as any).dataLayer = dataLayer || [];
|
||||||
|
function gtag(...x: any[]){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = dotGetter(g.config, "external.google.analytics");
|
||||||
|
if (id) {
|
||||||
|
gAnalytics(id);
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
const pug = require("pug");
|
import showdown from "showdown";
|
||||||
const showdown = require("showdown");
|
import h from "hyperscript";
|
||||||
const h = require("hyperscript");
|
|
||||||
|
|
||||||
class Markdown {
|
export class Markdown {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.converter = new showdown.Converter({
|
this.converter = new showdown.Converter({
|
||||||
parseImgDimensions: true
|
parseImgDimensions: true
|
||||||
@@ -33,25 +32,12 @@ class Markdown {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const md = new Markdown();
|
export const md = new Markdown();
|
||||||
|
export const pugFilters = {
|
||||||
module.exports = {
|
|
||||||
Markdown,
|
|
||||||
apply() {
|
|
||||||
cogear.on("preload.page.parse", (page) => {
|
|
||||||
if (page.format === ".pug") {
|
|
||||||
page.__content = pug.compile(page.__content || "", {
|
|
||||||
filters: {
|
|
||||||
markdown: (text) => {
|
markdown: (text) => {
|
||||||
return md.md2html(text)
|
return md.md2html(text);
|
||||||
}
|
},
|
||||||
}
|
css: (text) => {
|
||||||
})()
|
return h("style", {innerHTML: text});
|
||||||
page.format = ".html";
|
|
||||||
} else if (page.format === ".md") {
|
|
||||||
page.__content = md.md2html(page.__content || "")
|
|
||||||
page.format = ".html";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import SearchParser from "./search";
|
||||||
|
|
||||||
|
const p = new SearchParser();
|
||||||
|
|
||||||
|
describe("SearchParser.doParse", () => {
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"a",
|
||||||
|
"a:b",
|
||||||
|
"a:b c",
|
||||||
|
"a:b c:d",
|
||||||
|
"a:b OR c",
|
||||||
|
"date:2018-08-12",
|
||||||
|
"date>2018-08-12",
|
||||||
|
" tag:分类词汇"
|
||||||
|
].forEach((q) => {
|
||||||
|
it(q, () => {
|
||||||
|
console.dir(p.parseFull(q), {depth: null});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})
|
||||||
@@ -0,0 +1,396 @@
|
|||||||
|
/**
|
||||||
|
* Adapted from https://github.com/patarapolw/rep2recall-web/blob/master/src/node/engine/search.ts
|
||||||
|
*/
|
||||||
|
import uuid from "uuid/v4";
|
||||||
|
import moment from "moment";
|
||||||
|
import { g } from '@/shared';
|
||||||
|
|
||||||
|
export interface ISearchParserResult {
|
||||||
|
is: Set<string>;
|
||||||
|
sortBy: string | null;
|
||||||
|
desc: boolean | null;
|
||||||
|
cond: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class SearchParser {
|
||||||
|
public is: Set<string> = new Set();
|
||||||
|
public sortBy: string | null = null;
|
||||||
|
public desc: boolean | null = null;
|
||||||
|
|
||||||
|
private readonly anyOf: Set<string> | null = null;
|
||||||
|
private readonly isString = new Set(["title", "author", "tag"]);
|
||||||
|
private readonly isDate = new Set(["date"]);
|
||||||
|
|
||||||
|
public filterPosts(q: string): Record<string, any>[] {
|
||||||
|
const cond = this.parse(q);
|
||||||
|
|
||||||
|
let ps = g.posts;
|
||||||
|
if (this.sortBy) {
|
||||||
|
ps = ps.sort(sorter(this.sortBy, this.desc || false));
|
||||||
|
} else {
|
||||||
|
ps = ps.sort(sorter("date", true));
|
||||||
|
}
|
||||||
|
|
||||||
|
ps = ps.filter(mongoFilter(cond));
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public parse(q: string): Record<string, any> {
|
||||||
|
this.is = new Set();
|
||||||
|
this.sortBy = null
|
||||||
|
this.desc = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return this._parse(q);
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public parseFull(q: string): ISearchParserResult {
|
||||||
|
return {
|
||||||
|
cond: this.parse(q),
|
||||||
|
is: this.is,
|
||||||
|
sortBy: this.sortBy,
|
||||||
|
desc: this.desc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _parse(q: string): Record<string, any> {
|
||||||
|
q = q.trim();
|
||||||
|
|
||||||
|
for (const method of [
|
||||||
|
this.removeBrackets,
|
||||||
|
this.parseSep(" OR "),
|
||||||
|
this.parseSep(" "),
|
||||||
|
this.parseNeg,
|
||||||
|
this.parseFullExpr,
|
||||||
|
this.parsePartialExpr
|
||||||
|
]) {
|
||||||
|
try {
|
||||||
|
return method.bind(this)(q);
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeBrackets(q: string) {
|
||||||
|
if (q[0] === "(" && q[q.length - 1] === ")") {
|
||||||
|
return this.parse(q.substr(1, q.length - 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Not bracketed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseSep(sep: string) {
|
||||||
|
return (q: string) => {
|
||||||
|
const brackets: any = {};
|
||||||
|
|
||||||
|
q = q.replace(/\([^)]+\)/g, (p0) => {
|
||||||
|
const id = uuid();
|
||||||
|
brackets[id] = p0;
|
||||||
|
return id;
|
||||||
|
});
|
||||||
|
const tokens = q.split(sep);
|
||||||
|
tokens.forEach((t, i) => {
|
||||||
|
for (const k of Object.keys(brackets)) {
|
||||||
|
tokens[i] = tokens[i].replace(k, brackets[k]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tokens.length >= 2) {
|
||||||
|
const parsedTokens = tokens.map((t) => this._parse(t)).map((t) => t);
|
||||||
|
if (parsedTokens.length > 1) {
|
||||||
|
return { [sep === " OR " ? "$or" : "$and"]: parsedTokens };
|
||||||
|
} else {
|
||||||
|
return parsedTokens[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Not separated by '${sep}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseNeg(q: string) {
|
||||||
|
if (q[0] === "-") {
|
||||||
|
const sb = "-sortBy:";
|
||||||
|
if (q.startsWith(sb) && q !== sb) {
|
||||||
|
this.sortBy = q.substr(sb.length);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { $not: this.parse(q.substr(1)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Not negative");
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFullExpr(q: string) {
|
||||||
|
const m = /^([\w-]+)(:|~|[><]=?|=)([\S-]+|"[^"]+")$/.exec(q);
|
||||||
|
if (m) {
|
||||||
|
let [_, k, op, v]: any[] = m;
|
||||||
|
|
||||||
|
if (v.length > 2 && v[0] === '"' && v[v.length - 1] === '"') {
|
||||||
|
v = v.substr(1, v.length - 2);
|
||||||
|
} else {
|
||||||
|
const m1 = /^\d+(?:\.\d+)?$/.exec(v);
|
||||||
|
if (m1) {
|
||||||
|
v = parseFloat(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k === "is") {
|
||||||
|
if (v === "due") {
|
||||||
|
k = "nextReview";
|
||||||
|
op = "<=";
|
||||||
|
v = new Date();
|
||||||
|
} else if (v === "leech") {
|
||||||
|
k = "srsLevel";
|
||||||
|
op = "=";
|
||||||
|
v = 0;
|
||||||
|
} else if (v === "new") {
|
||||||
|
k = "nextReview";
|
||||||
|
op = "=";;
|
||||||
|
v = "NULL";
|
||||||
|
} else {
|
||||||
|
this.is.add(v);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} else if (k === "sortBy") {
|
||||||
|
this.sortBy = v;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op === ":") {
|
||||||
|
if (k === "due" || k === "nextReview") {
|
||||||
|
k = "nextReview";
|
||||||
|
v = "<="
|
||||||
|
} else if (k === "created" || k === "modified") {
|
||||||
|
v = "<=";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v === "NULL") {
|
||||||
|
v = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isDate.has(k)) {
|
||||||
|
if (v === "NOW") {
|
||||||
|
v = new Date();
|
||||||
|
} else if (typeof v === "string") {
|
||||||
|
const m1 = /^([-+]?\\d+)(\\S*)$/.exec(v);
|
||||||
|
let isMomentParsed = false;
|
||||||
|
if (m1) {
|
||||||
|
try {
|
||||||
|
v = moment().add(parseInt(m1[1]), m1[2] as any).toDate();
|
||||||
|
isMomentParsed = true;
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMomentParsed) {
|
||||||
|
try {
|
||||||
|
v = moment(v).toDate()
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (moment.isDate(v) && op === ":") {
|
||||||
|
// op = ">";
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (v) {
|
||||||
|
if (op === ":") {
|
||||||
|
if (typeof v === "string" || this.isString.has(k)) {
|
||||||
|
v = { $substr: v };
|
||||||
|
}
|
||||||
|
} else if (op === "~") {
|
||||||
|
v = { $regex: v.toString() };
|
||||||
|
} else if (op === ">=") {
|
||||||
|
v = { $gte: v };
|
||||||
|
} else if (op === ">") {
|
||||||
|
v = { $gt: v }
|
||||||
|
} else if (op === "<=") {
|
||||||
|
v = { $lte: v };
|
||||||
|
} else if (op === "<") {
|
||||||
|
v = { $lt: v };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { [k]: v };
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Not full expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private parsePartialExpr(q: string) {
|
||||||
|
if (q && q.indexOf(":") === -1) {
|
||||||
|
const orCond: any[] = [];
|
||||||
|
|
||||||
|
if (this.anyOf) {
|
||||||
|
for (const a of this.anyOf) {
|
||||||
|
if (this.isString.has(a)) {
|
||||||
|
orCond.push({ [a]: { $substr: q } });
|
||||||
|
} else {
|
||||||
|
orCond.push({ [a]: q });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {"*": {$substr: q}}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orCond.length > 1) {
|
||||||
|
return { $or: orCond };
|
||||||
|
} else if (orCond.length === 1) {
|
||||||
|
return orCond[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Not partial expression");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mongoFilter(cond: any) {
|
||||||
|
return (item: Record<string, any>): boolean => {
|
||||||
|
for (const k of Object.keys(cond)) {
|
||||||
|
if (k[0] === "$") {
|
||||||
|
if (k === "$and") {
|
||||||
|
return cond[k].every((x: Record<string, any>) => mongoFilter(x)(item));
|
||||||
|
} else if (k === "$or") {
|
||||||
|
return cond[k].some((x: Record<string, any>) => mongoFilter(x)(item));
|
||||||
|
} else if (k === "$not") {
|
||||||
|
return !mongoFilter(cond[k])(item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let itemK = dotGetter(item, k);
|
||||||
|
|
||||||
|
if (cond[k] && cond[k].constructor === {}.constructor
|
||||||
|
&& Object.keys(cond[k]).some((k0) => k0[0] === "$")) {
|
||||||
|
return (() => {
|
||||||
|
for (const op of Object.keys(cond[k])) {
|
||||||
|
try {
|
||||||
|
if (op === "$regex") {
|
||||||
|
if (Array.isArray(itemK)) {
|
||||||
|
return itemK.some(new RegExp(cond[k][op].toString(), "i").test);
|
||||||
|
} else {
|
||||||
|
return new RegExp(cond[k][op].toString(), "i").test(itemK);
|
||||||
|
}
|
||||||
|
} else if (op === "$startswith") {
|
||||||
|
if (Array.isArray(itemK)) {
|
||||||
|
return itemK.some((el) => el.startsWith(cond[k][op]));
|
||||||
|
} else {
|
||||||
|
return itemK.startsWith(cond[k][op]);
|
||||||
|
}
|
||||||
|
} else if (op === "$substr") {
|
||||||
|
|
||||||
|
if (Array.isArray(itemK)) {
|
||||||
|
return itemK.some((el: string) => el.includes(cond[k][op]));
|
||||||
|
} else {
|
||||||
|
return itemK.includes(cond[k][op]);
|
||||||
|
}
|
||||||
|
} else if (op === "$exists") {
|
||||||
|
return (itemK === null || itemK === undefined || itemK === "") === cond[k][op];
|
||||||
|
} else {
|
||||||
|
let v = itemK;
|
||||||
|
let v0 = cond[k][op];
|
||||||
|
try {
|
||||||
|
[v, v0] = [parseInt(v), parseInt(v0)];
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
|
if (op === "$gte") {
|
||||||
|
return v >= v0;
|
||||||
|
} else if (op === "$gt") {
|
||||||
|
return v > v0;
|
||||||
|
} else if (op === "$lte") {
|
||||||
|
return v <= v0;
|
||||||
|
} else if (op === "$lt") {
|
||||||
|
return v < v0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})();
|
||||||
|
} else if (Array.isArray(itemK)) {
|
||||||
|
if (!itemK.includes(cond[k])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (itemK !== cond[k]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dotGetter(d: any, k: string) {
|
||||||
|
let v = d;
|
||||||
|
for (const kn of k.split(".")) {
|
||||||
|
if (v && v.constructor === {}.constructor) {
|
||||||
|
if (kn === "*") {
|
||||||
|
v = Object.values(v);
|
||||||
|
} else {
|
||||||
|
v = v[kn];
|
||||||
|
if (v === undefined) {
|
||||||
|
v = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Array.isArray(v)) {
|
||||||
|
try {
|
||||||
|
v = v[parseInt(kn)];
|
||||||
|
if (v === undefined) {
|
||||||
|
v = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
v = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v && v.constructor === {}.constructor && Object.keys(v).length === 0) {
|
||||||
|
v = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sorter(sortBy?: string, desc?: boolean) {
|
||||||
|
return (a: any, b: any) => {
|
||||||
|
if (!sortBy) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const m = a[sortBy];
|
||||||
|
const n = b[sortBy];
|
||||||
|
|
||||||
|
if (typeof m === typeof n) {
|
||||||
|
if (typeof m === "string") {
|
||||||
|
return desc ? n.localeCompare(m) : m.localeCompare(n);
|
||||||
|
} else if (typeof m === "number") {
|
||||||
|
return desc ? n - m : m - n;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const typeDict = {
|
||||||
|
"number": 1,
|
||||||
|
"string": 2,
|
||||||
|
"object": 3
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const tM = typeDict[typeof m] || -1;
|
||||||
|
const tN = typeDict[typeof n] || -1;
|
||||||
|
|
||||||
|
return desc ? tN - tM : tM - tN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
---
|
|
||||||
shuffle: true
|
|
||||||
js:
|
|
||||||
- https://patarapolw.github.io/s2speak/index.min.js?key=x
|
|
||||||
---
|
|
||||||
|
|
||||||
罗马人的黄金时代已过去了。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 罗 马 luó mǎ Rome, capital of Italy
|
|
||||||
- 黄 金 时 代 huáng jīn shí dài golden age
|
|
||||||
- 已 yǐ already; to stop
|
|
||||||
- 过 去 guò qù (in the) past
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
黄河是中国的第二大河流。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 河 流 hé liú river
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
哲学上的玄想出自实际情况。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 哲 学 zhé xué philosophy
|
|
||||||
- 玄 xuán black; mysterious
|
|
||||||
- 想 出 xiǎng chū to figure out
|
|
||||||
- 实 际 情 况 shí jì qíng kuàng actual circumstances
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
宇宙毫无疑问是无限的。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 宇 宙 yǔ zhòu universe; cosmos
|
|
||||||
- 毫 无 疑 问 háo wú yí wèn certainty
|
|
||||||
- 无 限 wú xiàn unlimited
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
许多房屋被洪水冲走了。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 许 多 xǔ duō many; a lot of
|
|
||||||
- 房 屋 fáng wū house; building
|
|
||||||
- 被 bèi quilt; by
|
|
||||||
- 洪 水 hóng shuǐ deluge; flood
|
|
||||||
- 冲 走 chōng zǒu to flush away
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
多么荒唐的故事!
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 荒 唐 huāng táng beyond belief
|
|
||||||
- 故 事 gù shì old practice
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
我当初荒废了岁月。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 当 初 dāng chū at that time
|
|
||||||
- 荒 废 huāng fèi to abandon (cultivated fields)
|
|
||||||
- 岁 月 suì yuè years; time
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
资产盈利能力或一些其他的价值,它们的主人。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 资 产 zī chǎn property; assets
|
|
||||||
- 盈 利 yíng lì profit; gain
|
|
||||||
- 能 力 néng lì capability; ability
|
|
||||||
- 或 huò maybe; perhaps; or
|
|
||||||
- 一 些 yī xiē some; a few
|
|
||||||
- 其 他 qí tā other; the rest
|
|
||||||
- 价 值 jià zhí value; worth
|
|
||||||
- 主 人 zhǔ rén master; host; owner
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
庆祝历史上的每个圣人的诞辰
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 庆 祝 qìng zhù to celebrate
|
|
||||||
- 历 史 上 lì shǐ shàng historical
|
|
||||||
- 圣 人 shèng rén saint; sage
|
|
||||||
- 诞 辰 dàn chén birthday
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
那张CD是我儿子的。
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
---
|
|
||||||
shuffle: true
|
|
||||||
js:
|
|
||||||
- https://patarapolw.github.io/s2speak/index.min.js?key=x
|
|
||||||
---
|
|
||||||
|
|
||||||
一股寒流侵袭了欧洲。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 寒 流 hán liú cold stream
|
|
||||||
- 侵 袭 qīn xí to invade
|
|
||||||
- 欧 洲 ōu zhōu Europe
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
天气非常寒冷。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 寒 冷 hán lěng cold (climate)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
寒风席卷北方。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 席 卷 xí juǎn to engulf; to sweep
|
|
||||||
- 北 方 běi fāng north
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
暑假期间,我在邮局工作。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 暑 假 shǔ jià summer vacation
|
|
||||||
- 期 间 qī jiān period of time
|
|
||||||
- 邮 局 yóu jú post office
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他们去了爱丁堡避暑。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 爱 丁 堡 ài dīng bǎo Edinburgh, capital of Scotland
|
|
||||||
- 避 暑 bì shǔ to be away for the summer holidays
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
然而,相反的理论往往也是真的。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 然 而 rán ér however; yet; but
|
|
||||||
- 相 反 xiāng fǎn opposite; contrary
|
|
||||||
- 理 论 lǐ lùn theory; to argue
|
|
||||||
- 往 往 wǎng wǎng often; frequently
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
我不能再往前走了。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 往 前 wǎng qián to move forwards
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
春天和秋天,你更喜欢哪个?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
今年中秋节是星期一吗?
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 中 秋 节 zhōng qiū jié the Mid-Autumn Festival on 15th of 8th lunar month
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
你有没有收据?
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 收 据 shōu jù receipt
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
对不起。我收回我的话。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 收 回 shōu huí to regain
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
我今天收到了她的信。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 收 到 shōu dào to receive
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
西藏的好水就是世界的好水。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 西 藏 xī zàng Tibet
|
|
||||||
- 世 界 shì jiè world
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他把它藏在了门后。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
谁在影子里藏着?
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 影 子 yǐng zi shadow; reflection
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
我想知道这个冬天在我们的城市会不会下雪。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 城 市 chéng shì city; town
|
|
||||||
- 下 雪 xià xuě to snow
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
冬季是一年中最冷的季节。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 冬 季 dōng jì winter
|
|
||||||
- 年 中 nián zhōng within the year
|
|
||||||
- 季 节 jì jié time; season
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
我们为过冬储备了10吨煤。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 过 冬 guò dōng to get through the winter
|
|
||||||
- 储 备 chǔ bèi reserves
|
|
||||||
- 吨 dūn ton (loanword)
|
|
||||||
- 煤 méi coal
|
|
||||||
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
---
|
|
||||||
shuffle: true
|
|
||||||
js:
|
|
||||||
- https://patarapolw.github.io/s2speak/index.min.js?key=x
|
|
||||||
---
|
|
||||||
|
|
||||||
用闰表来测定的格林尼治时间。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 测 定 cè dìng to survey and evaluate
|
|
||||||
- 格 林 尼 治 gé lín ní zhì Greenwich (former location of Greenwich observatory, at zero longitude)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
闰的(闰日、闰年的)在日历中加入一天或一月而使历年与太阳年相吻合的
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 加 入 jiā rù to become a member
|
|
||||||
- 日 历 rì lì calendar
|
|
||||||
- 历 年 lì nián calendar year
|
|
||||||
- 吻 合 wěn hé to be a good fit
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
尽管现在中国人的生活越来越好了,可是还有改进的余地。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 尽 管 jǐn guǎn despite; although
|
|
||||||
- 越 来 越 yuè lái yuè more and more
|
|
||||||
- 改 进 gǎi jìn to improve
|
|
||||||
- 余 地 yú dì margin; leeway
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
你留在这儿,其余的人去外面
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 其 余 qí yú the rest; remaining
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他和我同岁。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
你多大岁数了?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
法律有很多不明确的地方。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 法 律 fǎ lǜ law
|
|
||||||
- 不 明 确 bù míng què indefinite; unclear
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
嚴以律己, 寬以待人。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 严 以 律 己 yǎn yǐ lǜ jǐ to be strict with oneself (idiom)
|
|
||||||
- 宽 以 待 人 kuān yǐ dài rén to be lenient with others (idiom)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
心里正在捉着迷藏,吕校长鞠躬请他演讲,下面一阵鼓掌。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 捉 zhuō to clutch; to grab
|
|
||||||
- 着 迷 zháo mí to be fascinated
|
|
||||||
- 校 长 xiào zhǎng (college, university) president
|
|
||||||
- 鞠 躬 jū gōng to bow
|
|
||||||
- 演 讲 yǎn jiǎng lecture
|
|
||||||
- 一 阵 yī zhèn a burst; a fit
|
|
||||||
- 鼓 掌 gǔ zhǎng to applaud; to clap
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他强调都市生活的便利方面。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 强 调 qiáng diào to emphasize (a statement)
|
|
||||||
- 都 市 dū shì city; metropolis
|
|
||||||
- 生 活 shēng huó life; activity
|
|
||||||
- 便 利 biàn lì convenient; easy
|
|
||||||
- 方 面 fāng miàn respect; aspect
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
现今人们没有空调无法生活。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 无 法 wú fǎ unable; incapable
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
众口难调。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
我想特别强调这一点。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
如果没有太阳,那所有生物都会死。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
住家的阳台都对着广
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 阳 台 yáng tái balcony; porch
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
这间房照不到很多阳光。
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
---
|
|
||||||
shuffle: true
|
|
||||||
js:
|
|
||||||
- https://patarapolw.github.io/s2speak/index.min.js?key=x
|
|
||||||
---
|
|
||||||
|
|
||||||
他们俩相爱已经多年。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
她特别地恨那个男孩。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
听了这消息我心里很不安。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
她的优点是临危不乱。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
多数旧电影片都是黑白的。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
这个墨颜色很黑。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
冰太薄,承受不住你的重量。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
厚厚的云把风景遮住了。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
我饱了,一点也吃不下了。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
这孩子不是肚子饿,就是馋嘴。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他的境遇很可悲。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
大厅里充满了他们的欢笑声。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他的背上有一个蛇形的红斑。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
病人服药后腹痛逐止。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
虽然笨,可是他很刻苦。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他很年轻,身子骨很灵巧。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
这本书的缺点是太长。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他把头发剪成时兴的短发。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他发誓要为父亲报仇。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
你不像是忘恩负义的人。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
安居乐业
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
黑名单
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
厚此薄彼
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
悲欢离合
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
笨手笨脚
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
日短夜长
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
恩将仇报
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
---
|
|
||||||
shuffle: true
|
|
||||||
js:
|
|
||||||
- https://patarapolw.github.io/s2speak/index.min.js?key=x
|
|
||||||
source: https://th.hujiang.com/new/p394824/
|
|
||||||
---
|
|
||||||
|
|
||||||
调味料
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
เครื่องปรุงรส
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
沙拉油
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
น้ำมันสลัด
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
蚝油
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
น้ำมันหอย
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
面包屑
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
เศษขนมปัง
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
酦粉
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
แป้งฟู
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
调味汁
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
น้ำปรุงรสอาหาร
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
面粉
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
แป้งข้าวสาลี
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
香料
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
เครื่องเทศ
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
盐
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
เกลือ
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
胡椒
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
พริกไทย
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
蕃茄酱
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
ซอสมะเขือเทศ
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
酱油
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
ซีอิ๊ว
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
糖
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
น้ำตาล
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
辣酱
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
ซอสพริก
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
醋
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
น้ำส้ม
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
黄油
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
เนย
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
花生酱
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
เนยถั่ว
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
椰浆
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
น้ำกะทิ
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
牛奶
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
นม
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
虾酱
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
กะปิ
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
鱼露
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
น้ำปลา
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
---
|
|
||||||
shuffle: true
|
|
||||||
js:
|
|
||||||
- https://patarapolw.github.io/s2speak/index.min.js?key=x
|
|
||||||
---
|
|
||||||
|
|
||||||
我们应当用右手拿着坚固的盾牌去捍卫我们在中东的利益。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 应 当 yīng dāng should; ought to
|
|
||||||
- 右 手 yòu shǒu right hand
|
|
||||||
- 拿 ná to hold; to seize
|
|
||||||
- 坚 固 jiān gù firm; firmly; hard
|
|
||||||
- 盾 牌 dùn pái shield; pretext
|
|
||||||
- 捍 卫 hàn wèi to defend
|
|
||||||
- 利 益 lì yì benefit
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
倾盆大雨劈头盖脸地浇了下来。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 倾 盆 大 雨 qīng pén dà yǔ a downpour
|
|
||||||
- 劈 头 盖 脸 pī tóu gài liǎn lit. splitting the head and covering the face (idiom)
|
|
||||||
- 浇 jiāo to pour liquid
|
|
||||||
- 下 来 xià lai to come down
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
我踢足球的時候弄傷了腿。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 踢 tī to kick
|
|
||||||
- 足 球 zú qiú soccer ball; soccer
|
|
||||||
- 弄 伤 nòng shāng to bruise
|
|
||||||
- 腿 tuǐ hip bone
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
你认为汤姆的腰围是多少?
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 汤 姆 tāng mǔ Tom (name)
|
|
||||||
- 腰 围 yāo wéi waist measurement
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
一定是有人偷了你的手錶。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 偷 tōu to steal; to pilfer
|
|
||||||
- 手 表 shǒu biǎo wrist watch
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
抡锤子的工作使胳膊上的肌肉结成了一块块硬疙瘩。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 抡 lūn to swing (one's arms, a heavy object)
|
|
||||||
- 锤 子 chuí zi hammer
|
|
||||||
- 胳 膊 gē bo arm
|
|
||||||
- 肌 肉 jī ròu muscle; flesh
|
|
||||||
- 结 成 jié chéng to form
|
|
||||||
- 硬 yìng hard; stiff; strong
|
|
||||||
- 疙 瘩 gē da swelling or lump on skin
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
吃些火腿。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 些 xiē some; few; several
|
|
||||||
- 火 腿 huǒ tuǐ ham
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
他脸上显出一副严肃的神色。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 脸 liǎn face
|
|
||||||
- 显 出 xiǎn chū to express
|
|
||||||
- 严 肃 yán sù solemn; grave
|
|
||||||
- 神 色 shén sè expression; look
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
鸟的翅膀相当于人的胳膊。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 翅 膀 chì bǎng wing
|
|
||||||
- 相 当 于 xiāng dāng yú equivalent to
|
|
||||||
- 胳 膊 gē bo arm
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
这事他早就扔在脖子后边了。
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
- 早 就 zǎo jiù already at an earlier time
|
|
||||||
- 扔 rēng to throw
|
|
||||||
- 脖 子 bó zi neck
|
|
||||||
- 后 边 hòu bian back; rear; behind
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"root": "."
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import Router from 'vue-router';
|
||||||
|
import Search from './views/Search.vue';
|
||||||
|
import Single from "./views/Single.vue";
|
||||||
|
import About from "./views/About.vue";
|
||||||
|
|
||||||
|
Vue.use(Router);
|
||||||
|
|
||||||
|
export default new Router({
|
||||||
|
mode: "history",
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Search },
|
||||||
|
{ path: '/tag/:tag', component: Search },
|
||||||
|
{ path: "/p/:y/:mo/:name", component: Single },
|
||||||
|
{ path: "/about", component: About }
|
||||||
|
]
|
||||||
|
});
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const g = {
|
||||||
|
q: "",
|
||||||
|
posts: POSTS,
|
||||||
|
config: CONFIG
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import Vue, { VNode } from 'vue'
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace JSX {
|
||||||
|
// tslint:disable no-empty-interface
|
||||||
|
interface Element extends VNode {}
|
||||||
|
// tslint:disable no-empty-interface
|
||||||
|
interface ElementClass extends Vue {}
|
||||||
|
interface IntrinsicElements {
|
||||||
|
[elem: string]: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
declare module '*.vue' {
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default Vue
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export function escapeRegExp(s: string) {
|
||||||
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeArray(it: any): any {
|
||||||
|
if (Array.isArray(it)) {
|
||||||
|
return it[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
b-card.p-3(v-html="content")
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component } from "vue-property-decorator";
|
||||||
|
import { md } from "@/plugins/render";
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class About extends Vue {
|
||||||
|
private content: string = "";
|
||||||
|
|
||||||
|
public mounted() {
|
||||||
|
this.content = md.md2html(README);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
div
|
||||||
|
h1.tag(v-if="$route.tag") {{$route.tag}}
|
||||||
|
div(v-if="posts && posts.length > 0")
|
||||||
|
post(v-for="p in posts" :filename="p.filename" :is-teaser="true" :key="p.filename")
|
||||||
|
b-pagination(v-model="page" :total-rows="count" :per-page="perPage")
|
||||||
|
div(v-else-if="posts")
|
||||||
|
empty
|
||||||
|
div(v-else)
|
||||||
|
first
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component, Prop, Watch } from "vue-property-decorator";
|
||||||
|
import Post from "@/layouts/Post.vue";
|
||||||
|
import Empty from "@/layouts/Empty.vue";
|
||||||
|
import First from "@/layouts/First.vue";
|
||||||
|
import SearchParser from "@/plugins/search";
|
||||||
|
import { normalizeArray } from "@/util";
|
||||||
|
import { g } from "@/shared";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
Post, Empty, First
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export default class Search extends Vue {
|
||||||
|
private posts?: any[] = [];
|
||||||
|
|
||||||
|
private g = g;
|
||||||
|
private page: number = 1;
|
||||||
|
private count: number = 0;
|
||||||
|
private perPage: number = 5;
|
||||||
|
|
||||||
|
public mounted() {
|
||||||
|
this.page = parseInt(normalizeArray(this.$route.query.page) || "1");
|
||||||
|
this.updatePosts();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Watch("g.q")
|
||||||
|
@Watch("page")
|
||||||
|
@Watch("$route.params")
|
||||||
|
private async updatePosts() {
|
||||||
|
const parser = new SearchParser();
|
||||||
|
let ps = this.$route.params.tag
|
||||||
|
? parser.filterPosts([this.g.q, `tag=${this.$route.params.tag}`].join(" "))
|
||||||
|
: parser.filterPosts(this.g.q);
|
||||||
|
|
||||||
|
const { perPage } = g.config.posts;
|
||||||
|
this.perPage = perPage;
|
||||||
|
this.count = ps.length;
|
||||||
|
|
||||||
|
ps = ps.filter((p, i) => {
|
||||||
|
const iPage = i / perPage;
|
||||||
|
return iPage >= this.page - 1 && iPage < this.page;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.posts = ps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
div
|
||||||
|
div(v-if="filename")
|
||||||
|
post(:is-teaser="false" :filename="filename")
|
||||||
|
vue-disqus(:shortname="disqus" :identifier="$route.path")
|
||||||
|
div(v-else="")
|
||||||
|
empty
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component, Prop } from "vue-property-decorator";
|
||||||
|
import Post from "@/layouts/Post.vue";
|
||||||
|
import Empty from "@/layouts/Empty.vue";
|
||||||
|
import moment from "moment";
|
||||||
|
import { g } from '../shared';
|
||||||
|
import { dotGetter } from '../plugins/search';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
Post, Empty
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export default class Search extends Vue {
|
||||||
|
private filename: string = "";
|
||||||
|
|
||||||
|
private disqus: string = dotGetter(g.config, "external.disqus");
|
||||||
|
|
||||||
|
public mounted() {
|
||||||
|
const ps = g.posts.filter((p) => {
|
||||||
|
const m = moment(p.date);
|
||||||
|
if (m.format("YYYY") === this.$route.params.y && m.format("MM") === this.$route.params.mo) {
|
||||||
|
if (p.filename
|
||||||
|
.replace(/^.*\//, "")
|
||||||
|
.replace(/\.[^.]+$/, "") === this.$route.params.name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!ps[0]) {
|
||||||
|
this.filename = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.filename = ps[0].filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# Cogear.JS theme **blog**
|
|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Theme with blog posts on the home page.
|
|
||||||
|
|
||||||
Simple responsive design. Posts tags support with navigation and pagination.
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
You need to install [`cogear-plugin-blog`](https://github.com/codemotion/cogear-plugin-blog) to use this theme.
|
|
||||||
|
|
||||||
Go to the site folder and install theme with command:
|
|
||||||
```bash
|
|
||||||
yarn add cogear-theme-blog
|
|
||||||
# or
|
|
||||||
npm install cogear-theme-blog
|
|
||||||
```
|
|
||||||
|
|
||||||
After that you need to edit your site `config.yaml` to set up installed theme.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
theme: blog
|
|
||||||
```
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
|
|
||||||
Use `cogear-plugin-blog` options in `./config.yaml`:
|
|
||||||
``` yaml
|
|
||||||
title: Blog | Cogear.JS – modern static websites generator
|
|
||||||
description:
|
|
||||||
keywords:
|
|
||||||
theme: blog
|
|
||||||
blog:
|
|
||||||
index: "" # Provide posts to index page
|
|
||||||
regex: "^p/"
|
|
||||||
tagUri: 'tag'
|
|
||||||
perPage: 5
|
|
||||||
pages:
|
|
||||||
^p/:
|
|
||||||
layout: post
|
|
||||||
author:
|
|
||||||
login: User
|
|
||||||
avatar: 'https://www.gravatar.com/avatar/400caf343d3bab57ab93f63e21a12be7?s=24'
|
|
||||||
link: https://cogearjs.org
|
|
||||||
```
|
|
||||||
# Usage
|
|
||||||
|
|
||||||
You may also want to install in with [`cogear-preset-blog`](https://github.com/codemotion/cogear-preset-blog).
|
|
||||||
|
|
||||||
# Docs
|
|
||||||
|
|
||||||
More info: [https://cogearjs.org/docs/themes](https://cogearjs.org/docs/themes).
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
article.post
|
|
||||||
header: h1 Write a post!
|
|
||||||
.post-content
|
|
||||||
p Go to <code>./src/pages/p</code> folder and create your first post, creating <code>first-post.md</code> file filled with the following content:
|
|
||||||
pre.
|
|
||||||
---
|
|
||||||
title: First post
|
|
||||||
tags:
|
|
||||||
- news
|
|
||||||
---
|
|
||||||
# This is my first post!
|
|
||||||
p Any questions? More info: <a href="https://github.com/codemotion/cogear-template-blog">https://github.com/codemotion/cogear-template-blog</a>
|
|
||||||
a(href="https://cogearjs.org"): img(src="https://cogearjs.org/images/cogearjs.jpg")
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
head
|
|
||||||
title=title
|
|
||||||
link(rel="shortcut icon" href=`${cogear.baseUrl}favicon.ico` type="image/png")
|
|
||||||
body
|
|
||||||
.navbar
|
|
||||||
.container
|
|
||||||
.brand
|
|
||||||
a(href="/") Blog
|
|
||||||
if cogear.blog.tags
|
|
||||||
ul
|
|
||||||
each t in cogear.blog.tags
|
|
||||||
- tName = t[0].toUpperCase() + t.slice(1)
|
|
||||||
li: a(href=`/tags/${t}`)= tName
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
mixin post(post)
|
|
||||||
.card.p-2.mb-3.post(class=`${post.teaser ? 'teaser' : 'full'}`)
|
|
||||||
.post-meta.mb-3
|
|
||||||
.float-right
|
|
||||||
+date(post.date)
|
|
||||||
.post-meta--author
|
|
||||||
a(href=`${post.author.link}`): img.mr-3(src=`${post.author.avatar}`)
|
|
||||||
a(href=`${post.author.link}`)= post.author.login
|
|
||||||
header
|
|
||||||
if post.teaser
|
|
||||||
h2: a(href=`${cogear.baseUrl}${post.uri}`)= post.title
|
|
||||||
else
|
|
||||||
h1= post.title
|
|
||||||
.post-content!= post.teaser ? post.teaser : post.content
|
|
||||||
if !post.teaser
|
|
||||||
ul.mt-3.pagination
|
|
||||||
li.page-item
|
|
||||||
a.page-link(href="javascript: history.back()") ← Back
|
|
||||||
mixin date(date)
|
|
||||||
- let months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
|
|
||||||
- let d = new Date(date)
|
|
||||||
- month = months[d.getMonth()]
|
|
||||||
time= `${month} ${d.getDate()}`
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
extends layout.pug
|
|
||||||
block head
|
|
||||||
if tag
|
|
||||||
- tagName = tag[0].toUpperCase() + tag.slice(1)
|
|
||||||
- title= `${tagName} | ${title}`
|
|
||||||
if paginator && paginator.current > 1
|
|
||||||
- title = `Page ${paginator.current} | ${title}`
|
|
||||||
title= title
|
|
||||||
block content
|
|
||||||
if tag
|
|
||||||
h1.tag= tagName
|
|
||||||
//- if content
|
|
||||||
//- article.page!= content
|
|
||||||
if posts
|
|
||||||
- let now = new Date()
|
|
||||||
each post in posts
|
|
||||||
if new Date(post.date) < now
|
|
||||||
+post(post)
|
|
||||||
include paginator
|
|
||||||
else
|
|
||||||
include includes/empty
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
include includes/mixins
|
|
||||||
head
|
|
||||||
block head
|
|
||||||
title= title
|
|
||||||
meta(content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1.0, maximum-scale=1" name="viewport")
|
|
||||||
meta(charset="UTF-8")
|
|
||||||
//- link(rel="shortcut icon" href=`${cogear.baseUrl}favicon.png` type="image/png")
|
|
||||||
link(rel="apple-touch-icon" sizes="180x180" href=`/apple-touch-icon.png`)
|
|
||||||
link(rel="icon" type="image/png" sizes="32x32" href=`/favicon-32x32.png`)
|
|
||||||
link(rel="icon" type="image/png" sizes="16x16" href=`/favicon-16x16.png`)
|
|
||||||
link(rel="manifest" href=`/site.manifest`)
|
|
||||||
link(rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css' integrity='sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T' crossorigin='anonymous')
|
|
||||||
body
|
|
||||||
nav.navbar.navbar-dark.bg-success.navbar-expand-lg
|
|
||||||
a.ml-3.navbar-brand(href="/")= cogear.config.blog.title || "BLOG"
|
|
||||||
|
|
||||||
button.navbar-toggler(data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false")
|
|
||||||
span.navbar-toggler-icon
|
|
||||||
.collapse.navbar-collapse#navbarSupportedContent
|
|
||||||
if cogear.config.blog.tags
|
|
||||||
ul.navbar-nav.mr-auto
|
|
||||||
each t in cogear.config.blog.tags
|
|
||||||
- tName = t[0].toUpperCase() + t.slice(1)
|
|
||||||
li.nav-item: a.nav-link(href=`/tag/${t}`)= tName
|
|
||||||
.container.mt-3
|
|
||||||
.row
|
|
||||||
.col-lg-8.col-md-12
|
|
||||||
block content
|
|
||||||
.col-lg-4.col-md-12
|
|
||||||
include sidebar
|
|
||||||
|
|
||||||
script(src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.slim.min.js')
|
|
||||||
script(src='https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js' integrity='sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1' crossorigin='anonymous')
|
|
||||||
script(src='https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js' integrity='sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM' crossorigin='anonymous')
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
if paginator
|
|
||||||
nav.mt-3
|
|
||||||
ul.pagination
|
|
||||||
if paginator.prev !== null
|
|
||||||
li.page-item
|
|
||||||
a.page-link(href=`${cogear.baseUrl}${paginator.prev}`) ← Prev
|
|
||||||
- let page = 1
|
|
||||||
while page <= paginator.total
|
|
||||||
- let range = 2
|
|
||||||
if page == 1 || page == paginator.total || (page >= paginator.current - range && page <= paginator.current + range)
|
|
||||||
if page == paginator.current
|
|
||||||
li.page-item.active
|
|
||||||
a.page-link(href=`${paginator.baseUri}/${page}`)= page
|
|
||||||
else
|
|
||||||
li.page-item
|
|
||||||
a.page-link(href=`${paginator.baseUri}/${page}`)= page
|
|
||||||
else if paginator.current < paginator.total - range && page == paginator.total - 1 || paginator.current > 1+range && page == range
|
|
||||||
li.page-item
|
|
||||||
a.page-link.ellipsis …
|
|
||||||
- page=page+1
|
|
||||||
if paginator.next !== null
|
|
||||||
li.page-item
|
|
||||||
a.page-link(href=`/${paginator.next}`) Next →
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
extends layout.pug
|
|
||||||
block content
|
|
||||||
+post({
|
|
||||||
title:title,
|
|
||||||
teaser: false,
|
|
||||||
tags:tags,
|
|
||||||
content:content,
|
|
||||||
date:date,
|
|
||||||
author: author
|
|
||||||
})
|
|
||||||
|
|
||||||
#disqus_thread
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
aside.card.p-3
|
|
||||||
block sidebar
|
|
||||||
:markdown-it
|
|
||||||
#### Record my journey to Chinese by [@polvcode](https://polvcode.dev)
|
|
||||||
|
|
||||||
Highlight text and press "s" to speak.
|
|
||||||
|
|
||||||
a.twitter-timeline(href="https://twitter.com/ChinesePol" data-height="600") Tweets by ChinesePol
|
|
||||||
script(async src="https://platform.twitter.com/widgets.js" charset="utf-8")
|
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 62 KiB |
@@ -1 +0,0 @@
|
|||||||
import "./theme.scss";
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
.post {
|
|
||||||
.post-meta {
|
|
||||||
img {
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"importHelpers": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"types": [
|
||||||
|
"webpack-env",
|
||||||
|
"mocha"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"scripthost"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue",
|
||||||
|
"tests/**/*.ts",
|
||||||
|
"tests/**/*.tsx"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
require = require("esm")(module)
|
||||||
|
const glob = require("fast-glob");
|
||||||
|
const fs = require("fs");
|
||||||
|
const { pugFilters } = require("./src/plugins/render");
|
||||||
|
const matter = require("gray-matter");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
|
function configureWebpack(webpackConfig) {
|
||||||
|
for (const rule of webpackConfig.module.rules) {
|
||||||
|
if (rule.use) {
|
||||||
|
for (const use of rule.use) {
|
||||||
|
if (/pug/.test(use.loader)) {
|
||||||
|
use.options = {filters: pugFilters};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (rule.oneOf) {
|
||||||
|
for (const oneOf of rule.oneOf) {
|
||||||
|
if (oneOf.use) {
|
||||||
|
for (const use of oneOf.use) {
|
||||||
|
if (/pug/.test(use.loader)) {
|
||||||
|
use.options = {filters: pugFilters};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(webpackConfig.devServer || {}).port = 8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function defineWebpack(webpackConfig, def) {
|
||||||
|
webpackConfig.plugin("define").tap((args) => {
|
||||||
|
args[0] = {
|
||||||
|
...args[0],
|
||||||
|
...def
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateDefinitions() {
|
||||||
|
return {
|
||||||
|
POSTS: JSON.stringify(fs.existsSync("public/posts")
|
||||||
|
? (await glob("public/posts/**/*.{md,markdown,pug,html}")).map((f) => {
|
||||||
|
const { data, content } = matter(fs.readFileSync(f, "utf8"));
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
teaser: content.split("===")[0],
|
||||||
|
filename: f
|
||||||
|
}
|
||||||
|
}) : []),
|
||||||
|
CONFIG: JSON.stringify(yaml.safeLoad(fs.readFileSync("config.yaml", "utf8"))),
|
||||||
|
README: JSON.stringify(fs.readFileSync("README.md", "utf8"))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (api, options) => {
|
||||||
|
api.registerCommand('build:async', async (args) => {
|
||||||
|
const def = await generateDefinitions();
|
||||||
|
|
||||||
|
api.configureWebpack(configureWebpack);
|
||||||
|
api.chainWebpack((webpackConfig) => {
|
||||||
|
defineWebpack(webpackConfig, def);
|
||||||
|
});
|
||||||
|
|
||||||
|
await api.service.run('build', args)
|
||||||
|
}),
|
||||||
|
api.registerCommand('serve:async', async (args) => {
|
||||||
|
const def = await generateDefinitions();
|
||||||
|
|
||||||
|
api.configureWebpack(configureWebpack);
|
||||||
|
api.chainWebpack((webpackConfig) => {
|
||||||
|
defineWebpack(webpackConfig, def);
|
||||||
|
});
|
||||||
|
|
||||||
|
await api.service.run('serve', args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.defaultModes = {
|
||||||
|
'build:async': 'production',
|
||||||
|
'serve:async': 'development'
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
publicPath: "/"
|
||||||
|
}
|
||||||