├── .dockerignore
├── .eslintrc.js
├── .gitignore
├── .travis.yml
├── .vscode
└── settings.json
├── ASSETS
├── ov-desktop.png
└── ov-mobile.png
├── Dockerfile
├── README.md
├── commitlint.config.js
├── config
├── env.js
├── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── paths.js
├── polyfills.js
├── test.setting.js
├── webpack.config.dev.js
├── webpack.config.prod.js
└── webpackDevServer.config.js
├── doc
├── assets
│ ├── netease-music.png
│ └── oauth.png
└── how-to-use.md
├── package-lock.json
├── package.json
├── prettier.config.js
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── scripts
├── build.js
├── crontab
├── install.sh
├── prod-server.js
├── start.js
├── test.js
└── update.sh
└── src
├── assets
└── img
│ ├── 404.svg
│ └── put-down.svg
├── common
├── RootRouter.jsx
├── configureStore.js
├── constant.js
├── global.styl
├── pageConfApi.js
├── registerServiceWorker.js
└── rootRouter.jsx
├── components
├── Gitalk
│ ├── gitalk.styl
│ └── index.js
├── MainLayout
│ ├── index.js
│ └── mainLayout.styl
├── NetEaseMusic
│ ├── index.js
│ └── netEaseMusic.styl
├── NotFound
│ ├── NotFound.spec.js
│ ├── index.js
│ └── sectionItem.styl
└── SectionItem
│ ├── index.js
│ └── sectionItem.styl
├── config
├── index-example.js
├── index.styl
└── pageConf.js
├── features
├── Article
│ ├── Article.jsx
│ ├── article.styl
│ └── index.js
├── Count
│ ├── Count.jsx
│ └── index.js
├── Footer
│ ├── Footer.jsx
│ ├── footer.styl
│ └── index.js
├── LinkSection
│ ├── BlankSection.jsx
│ ├── LabelSection.jsx
│ ├── LinkSection.jsx
│ ├── blankSection.styl
│ ├── index.js
│ ├── labelSection.styl
│ └── linkSection.styl
├── Loading
│ ├── Loading.jsx
│ ├── index.js
│ ├── loading.styl
│ └── loadingKeyFrames.styl
├── Nav
│ ├── ChangeMode.jsx
│ ├── ConnectChangeMode.js
│ ├── Header.jsx
│ ├── header.styl
│ └── index.js
├── Post
│ ├── Post.jsx
│ ├── index.js
│ └── post.styl
├── UserSection
│ ├── UserSection.jsx
│ ├── index.js
│ ├── scrollAni.js
│ └── userSection.styl
├── count
│ └── index.js
└── nav
│ ├── header.styl
│ └── index.js
├── index.js
├── reducers
├── index.js
├── page.js
└── user.js
├── routes
├── article.js
├── home.js
├── label.js
└── notFound.js
└── utils
├── github.js
└── utils.styl
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | build/
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: 'react-app',
3 | plugins: [ 'prettier' ],
4 | rules: {
5 | 'prettier/prettier': process.env.NODE_ENV === 'production' ? 'warn': 'error'
6 | }
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | /src/config/index.js
4 |
5 | TODO.md
6 |
7 | # dependencies
8 | /node_modules
9 |
10 | # testing
11 | /coverage
12 |
13 | # production
14 | /build
15 |
16 | # misc
17 | .DS_Store
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 |
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | nodejs:
3 | - stable
4 | env:
5 | global:
6 | - BASE_IMAGE=node
7 | notifications:
8 | email:
9 | on_success: never
10 | on_failure: always
11 |
12 | before_install:
13 | - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
14 | - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
15 | - sudo apt-get update
16 | - sudo apt-get -y install docker-ce
17 | script:
18 | - chmod u+x ./scripts/install.sh
19 | - ./scripts/install.sh
20 | - docker build -t ${IMAGE_NAME}:latest .
21 |
22 | before_deploy:
23 | - docker login -u ${DOCKER_LOGIN_USER_NAME} -p ${DOCKER_LOGIN_PASSWORD}
24 | - docker tag "${IMAGE_NAME}:latest" "${DOCKER_LOGIN_USER_NAME}/${IMAGE_NAME}:latest"
25 |
26 | deploy:
27 | skip_cleanup: true
28 | provider: script
29 | script: docker push "${DOCKER_LOGIN_USER_NAME}/${IMAGE_NAME}:latest"
30 | on:
31 | branch: master
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "Blogsue",
4 | "Gitalk",
5 | "cnpm",
6 | "coderming",
7 | "orgs",
8 | "repo"
9 | ]
10 | }
--------------------------------------------------------------------------------
/ASSETS/ov-desktop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoderMing/blogsue/9d98c041b108198a052d2f9e9e4f37ef8423910b/ASSETS/ov-desktop.png
--------------------------------------------------------------------------------
/ASSETS/ov-mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoderMing/blogsue/9d98c041b108198a052d2f9e9e4f37ef8423910b/ASSETS/ov-mobile.png
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node
2 |
3 | WORKDIR /app
4 | COPY . /app
5 |
6 | ADD /scripts/crontab /etc/cron.d/cron
7 | RUN chmod 0644 /etc/cron.d/cron
8 |
9 | RUN apt-get update && apt-get -y install cron
10 |
11 | RUN git remote remove origin \
12 | && git remote add origin https://github.com/coderming/blogsue.git
13 |
14 | RUN chmod +x /app/scripts/update.sh
15 |
16 | RUN npm config set registry "https://registry.npm.taobao.org/" \
17 | && npm install \
18 | && npm run build
19 |
20 | EXPOSE 8080
21 |
22 | CMD ["node","scripts/prod-server.js"]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Blogsue —— 基于 Github Issues 的博客系统
2 |
3 |
4 |
5 | 本项目是基于 GitHub Issues 的博客系统,技术栈为 React 全家桶。
6 |
7 | 很早以前,就有各路大佬开始使用 Github Issues 做自己的博客了。但其博客有诸多不足之处。例如不能禁止他人发 issue,不能自定义样式,不能搭建在自己的域名下等等。
8 |
9 | 项目的目的是为了弥补 GitHub Issues 的问题,具有以下功能:
10 |
11 | - 傻瓜式操作,只需填写一份配置文件即可使用
12 | - 支持 GitHub Pages(需采用 hash 路由模式
13 | - **已集成[Gitalk](https://github.com/gitalk/gitalk)评论系统**,文章的评论即为对应 issue 的 comment
14 | - **支持夜间模式**
15 | - 可筛选显示在博客上面的 issue 作者,防止他人发 issue 污染博客
16 | - 移动端适配,同时支持 PWA
17 | - Labels 做为博客标签云,支持通过 label 快速筛选文章
18 | - 支持 Docker 一键打包/部署
19 |
20 | ## 界面展示
21 |
22 | 预览:[CoderMing 的个人博客](https://www.coderming.com)
23 |
24 | PC 端:
25 |
26 | 手机端:
27 |
28 | ## 使用教程
29 |
30 | **[请点击这里](./doc/how-to-use.md)**
31 |
32 | ## 使用本项目的博客
33 |
34 | 如果你的博客使用了本项目,可以发 issue 并附上链接,我会尽快更新至本列表。
35 |
36 | - [CoderMing 的个人博客](https://www.coderming.com)
37 |
38 | ## 参与本项目
39 |
40 | 欢迎大家发 issue,提 PR。
41 |
42 | 受阅历限制,本项目定有诸多不完善的地方。如果您觉得项目中有可以优化的地方,请提出来,我会进行修改与完善。
43 |
44 | ## 联系
45 |
46 | [@CoderMing](https://www.coderming.com)
47 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 中文化 commitlit 规范
3 | */
4 | module.exports = {
5 | extends: ['@commitlint/config-conventional'],
6 | rules: {
7 | 'subject-case': [0, 'never', ['lower-case']] // 为了适配中文
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/config/env.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 | const paths = require('./paths')
4 |
5 | // Make sure that including paths.js after env.js will read .env variables.
6 | delete require.cache[require.resolve('./paths')]
7 |
8 | const NODE_ENV = process.env.NODE_ENV
9 | if (!NODE_ENV) {
10 | throw new Error('The NODE_ENV environment variable is required but was not specified.')
11 | }
12 |
13 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
14 | var dotenvFiles = [
15 | `${paths.dotenv}.${NODE_ENV}.local`,
16 | `${paths.dotenv}.${NODE_ENV}`,
17 | // Don't include `.env.local` for `test` environment
18 | // since normally you expect tests to produce the same
19 | // results for everyone
20 | NODE_ENV !== 'test' && `${paths.dotenv}.local`,
21 | paths.dotenv
22 | ].filter(Boolean)
23 |
24 | // Load environment variables from .env* files. Suppress warnings using silent
25 | // if this file is missing. dotenv will never modify any environment variables
26 | // that have already been set. Variable expansion is supported in .env files.
27 | // https://github.com/motdotla/dotenv
28 | // https://github.com/motdotla/dotenv-expand
29 | dotenvFiles.forEach(dotenvFile => {
30 | if (fs.existsSync(dotenvFile)) {
31 | require('dotenv-expand')(
32 | require('dotenv').config({
33 | path: dotenvFile
34 | })
35 | )
36 | }
37 | })
38 |
39 | // We support resolving modules according to `NODE_PATH`.
40 | // This lets you use absolute paths in imports inside large monorepos:
41 | // https://github.com/facebookincubator/create-react-app/issues/253.
42 | // It works similar to `NODE_PATH` in Node itself:
43 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
44 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
45 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
46 | // https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
47 | // We also resolve them to make sure all tools using them work consistently.
48 | const appDirectory = fs.realpathSync(process.cwd())
49 | process.env.NODE_PATH = (process.env.NODE_PATH || '')
50 | .split(path.delimiter)
51 | .filter(folder => folder && !path.isAbsolute(folder))
52 | .map(folder => path.resolve(appDirectory, folder))
53 | .join(path.delimiter)
54 |
55 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
56 | // injected into the application via DefinePlugin in Webpack configuration.
57 | const REACT_APP = /^REACT_APP_/i
58 |
59 | function getClientEnvironment(publicUrl) {
60 | const raw = Object.keys(process.env)
61 | .filter(key => REACT_APP.test(key))
62 | .reduce(
63 | (env, key) => {
64 | env[key] = process.env[key]
65 | return env
66 | },
67 | {
68 | // Useful for determining whether we’re running in production mode.
69 | // Most importantly, it switches React into the correct mode.
70 | NODE_ENV: process.env.NODE_ENV || 'development',
71 | // Useful for resolving the correct path to static assets in `public`.
72 | // For example,
.
73 | // This should only be used as an escape hatch. Normally you would put
74 | // images into the `src` and `import` them in code to get their paths.
75 | PUBLIC_URL: publicUrl,
76 |
77 | ROUTE_MODE: process.env.ROUTE_MODE || 'browser'
78 | }
79 | )
80 | // Stringify all values so we can feed into Webpack DefinePlugin
81 | const stringified = {
82 | 'process.env': Object.keys(raw).reduce((env, key) => {
83 | env[key] = JSON.stringify(raw[key])
84 | return env
85 | }, {})
86 | }
87 |
88 | return { raw, stringified }
89 | }
90 |
91 | module.exports = getClientEnvironment
92 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/en/webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const fs = require('fs')
3 | const url = require('url')
4 |
5 | // Make sure any symlinks in the project folder are resolved:
6 | // https://github.com/facebookincubator/create-react-app/issues/637
7 | const appDirectory = fs.realpathSync(process.cwd())
8 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath)
9 |
10 | const envPublicUrl = process.env.PUBLIC_URL
11 |
12 | function ensureSlash(path, needsSlash) {
13 | const hasSlash = path.endsWith('/')
14 | if (hasSlash && !needsSlash) {
15 | return path.substr(path, path.length - 1)
16 | } else if (!hasSlash && needsSlash) {
17 | return `${path}/`
18 | } else {
19 | return path
20 | }
21 | }
22 |
23 | const getPublicUrl = appPackageJson => envPublicUrl || require(appPackageJson).homepage
24 |
25 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
26 | // "public path" at which the app is served.
27 | // Webpack needs to know it to put the right