github:https://github.com/TryGhost/Ghost
docker [ghost]:https://hub.docker.com/_/ghost
docker [mysql]:https://hub.docker.com/_/mysql
1 mysql
1.1 数据文件映射
# 启动临时环境mysql8,并复制mysql8的数据文件到主机目录
docker run -dit --rm --name mysql8 -e MYSQL_ROOT_PASSWORD=root mysql:8 # 启动mysql8
docker ps -a # 查看mysql8对应的容器ID
mkdir -p /cz/docker/mysql # 创建目录
docker cp b9214b7b1a42:/var/lib/mysql /cz/docker/mysql/data # 复制容器的数据文件到主机目录下
docker stop mysql8 # 停止
1.2 启动
docker run -dit --rm --name mysql8 \
-v /cz/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-p 3306:3306 \
--log-opt max-size=1000m --log-opt max-file=3 \
mysql:8
2 ghost
2.1 数据文件映射
# 启动
docker run -dit --rm --name ghost \
-e NODE_ENV=production \
-e url=https://blog.cooperzhu.com \
-e database__client=mysql \
-e database__connection__host=192.168.1.163 \
-e database__connection__port=3306 \
-e database__connection__user=root \
-e database__connection__password=root \
-e database__connection__database=ghost \
-p 2368:2368 \
--log-opt max-size=1000m --log-opt max-file=3 \
ghost:5
mkdir -p /cz/docker/ghost/data # 创建目录
# 复制容器的数据文件到主机目录下
docker cp 4e03f25b3e59:/var/lib/ghost/content /cz/docker/ghost/data/content
docker cp 4e03f25b3e59:/var/lib/ghost/content.orig /cz/docker/ghost/data/content.orig
docker stop ghost # 停止
2.2 启动
docker run -dit --rm --name ghost \
-e NODE_ENV=production \
-e url=http://localhost:2368 \
-e database__client=mysql \
-e database__connection__host=192.168.1.163 \
-e database__connection__port=3306 \
-e database__connection__user=root \
-e database__connection__password=root \
-e database__connection__database=ghost \
-p 2368:2368 \
-v /cz/docker/ghost/data/content:/var/lib/ghost/content \
-v /cz/docker/ghost/data/content.orig:/var/lib/ghost/content.orig \
--log-opt max-size=1000m --log-opt max-file=3 \
ghost:5
博客后台地址:http://localhost:2368/ghost
2.3 配置
博客后台地址:http://localhost:2368/ghost
2.3.1 为md生成导航目录
tocbot:https://tscanlin.github.io/tocbot/
路径:Settings-->Code injection
下载相关js和css,并上传至content/themes/<主题名称>/assets目录下。
2.3.1.1 Site Header
<script src="/assets/tocbot@4.21.0/tocbot.min.js"></script>
<link href="/assets/tocbot@4.21.0/tocbot.min.css" rel="stylesheet">
<style>
.gh-content {
position: relative;
}
.gh-toc > .toc-list {
position: relative;
}
.toc-list {
overflow: hidden;
list-style: none;
}
.gh-toc-container li a:first-child::before {
position: relative;
content: "|";
font-weight: bolder;
margin-right: 0.8rem;
color: #2d96bd;
}
.gh-toc-container li a:first-child {
margin: 0;
}
.gh-toc .is-active-link::before {
background: solid 3px var(--ghost-accent-color); /* Defines TOC accent color based on Accent color set in Ghost Admin */
font-weight: bolder;
margin-right: .5rem;
color: var(--ghost-accent-color);
}
.gh-toc-container .is-active-link:first-child::before {
color: var(--ghost-accent-color);
}
.gh-toc .is-active-link {
color: var(--ghost-accent-color)
}
@media (min-width: 1000px) {
.gh-sidebar {
position: absolute;
top: 0;
bottom: 0;
margin-top: 4vmin;
margin-left: 20px;
grid-column: wide-end / main-end; /* Place the TOC to the right of the content */
width: inline-block;
white-space: nowrap;
border-left: 4px solid #f0f0f0;
padding: 0 .8rem;
overflow-wrap: break-word;
}
.gh-toc-container {
position: sticky; /* On larger screens, TOC will stay in the same spot on the page */
top: 4vmin;
max-width: 300px;
margin-left: 0.5rem;
}
.gh-toc-container .gh-toc-toggle {
display: none;
}
.gh-toc-container .gh-toc > .toc-list {
padding-left: 0;
margin-left: 0;
}
}
@media (max-width: 1000px) {
.gh-toc-container > div {
background-color: #EDEDED;
}
.gh-toc-container .gh-toc-title {
padding-left: 0.8rem;
}
.gh-toc-container .gh-toc-toggle {
display: block;
}
.toc-toggle-arrow {
border: solid #A9A9B3;
border-width: 0 3px 3px 0;
display: inline-block;
padding: 3px;
margin: 0.8rem 0;
}
.toc-toggle-arrow-right {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.toc-toggle-arrow-up {
transform: rotate(-135deg);
-webkit-transform: rotate(-135deg);
}
.gh-toc-container .gh-toc {
display: none;
}
.gh-toc-container .gh-toc.show {
display: block;
background-color: #F5F5F5;
}
.gh-toc-container .gh-toc > .toc-list {
padding-left: 0;
margin-left: 0.8rem;
}
}
</style>
2.3.1.2 Site Footer
<script>
function initTocbot(collapseDepth) {
tocbot.init({
tocSelector: '.gh-toc',
contentSelector: '.gh-content',
headingSelector: 'h1, h2, h3, h4',
hasInnerContainers: true,
collapseDepth: collapseDepth,
});
}
function changeDisplay() {
// Get the table of contents element
const toc = document.querySelector(".gh-toc");
const sidebar = document.querySelector(".gh-sidebar");
// Check the number of items in the table of contents
const tocItems = toc.querySelectorAll('li').length;
// Only show the table of contents if it has more than 5 items
if (tocItems > 2) {
sidebar.style.display = 'block';
} else {
sidebar.style.display = 'none';
}
}
/**
<aside class="gh-sidebar">
<div class="gh-toc-container">
<div style="font-weight: bold;">
Table of Contents
<span style="float: right; margin-right: 0.2rem;"></span>
</div>
<div class="gh-toc">
</div>
</div>
</aside>
*/
function initSidebar() {
const parent = document.querySelector(".gh-content.gh-canvas");
if (!parent) {
return;
}
const asideElement = document.createElement("aside");
asideElement.setAttribute("class", "gh-sidebar");
// Create the container div for title and TOC
const containerElement = document.createElement("div");
containerElement.setAttribute("class", "gh-toc-container");
// Create the title element
const titleElement = document.createElement("div");
titleElement.setAttribute("class", "gh-toc-title");
titleElement.textContent = "CONTENTS";
titleElement.style.fontWeight = "bold";
containerElement.appendChild(titleElement);
const toggleElement = document.createElement("span");
toggleElement.setAttribute("class", "gh-toc-toggle toc-toggle-arrow toc-toggle-arrow-right");
toggleElement.style.float = "right";
toggleElement.style.marginRight = "0.8rem";
titleElement.appendChild(toggleElement);
// Create the <div> element for TOC
const divElement = document.createElement("div");
divElement.setAttribute("class", "gh-toc");
containerElement.appendChild(divElement);
// Append the <div> element to the <aside> element
asideElement.appendChild(containerElement);
parent.insertBefore(asideElement, parent.firstChild);
//parent.appendChild(asideElement);
titleElement.addEventListener("click", function(e) {
divElement.classList.toggle("show");
toggleElement.classList.toggle("toc-toggle-arrow-right");
toggleElement.classList.toggle("toc-toggle-arrow-up");
initTocbot (3);
});
}
initSidebar();
initTocbot(1);
</script>
2.3.1.3 效果
2.3.2 代码块highlight
prism: https://prismjs.com/
路径:Settings-->Code injection
下载相关js和css,并上传至content/themes/<主题名称>/assets目录下。
推荐plugins:
- Line Numbers
- Autolinker
- Show Language
- Highlight Keywords
- Inline color
- Previewers
- Copy to Clipboard Button
2.3.2.1 Site Header
<script src="/assets/prism/prism.js"></script>
<link rel="stylesheet" href="/assets/prism/prism.css">
2.3.2.2 Site footer
<script>
function initPrism() {
// 初始化Line Numbers plugin
const children = document.querySelectorAll("pre > code");
for (var i = 0, len = children.length; i < len; i++) {
children[i].parentElement.classList.add("line-numbers");
}
}
initPrism();
</script>
2.3.2.3 效果
见本文章