Skip to content

Commit

Permalink
feat: 支持显示图片
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Jun 21, 2023
1 parent 9bca37e commit a9a8a0d
Show file tree
Hide file tree
Showing 16 changed files with 397 additions and 145 deletions.
11 changes: 6 additions & 5 deletions components/default/Detail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@

<script setup lang="ts">
import { usePost } from "~/composables/usePost"
import { checkExpires, getFirstImageSrc, getSummery } from "~/utils/utils"
import { checkExpires, getSummery } from "~/utils/utils"
import { createAppLogger } from "~/common/appLogger"
import { JsonUtil, StrUtil } from "zhi-common"
import { PostStatusEnum } from "zhi-blog-api"
import { JsonUtil } from "zhi-common"
import { useDom } from "~/composables/useDom"
const logger = createAppLogger("share-page")
Expand All @@ -43,6 +43,7 @@ const props = defineProps({
})
const { t } = useI18n()
const { getFirstImageSrc } = useDom()
const { currentPost, setCurrentPost } = usePost()
await setCurrentPost(props.pageId)
Expand All @@ -55,7 +56,7 @@ if (!props.overrideSeo) {
const titleSign = " - " + t("blog.share")
const title = `${currentPost.post.title}${props.showTitleSign ? titleSign : ""}`
const desc = getSummery(currentPost.post.description)
const headImage = await getFirstImageSrc(currentPost.post.description)
const headImage = getFirstImageSrc(currentPost.post.description)
const seoMeta = {
title: title,
ogTitle: title,
Expand Down Expand Up @@ -100,7 +101,7 @@ const VNode = () =>
contenteditable="false"
data-doc-type="NodeDocument"
>
<VNode v-highlight />
<VNode v-highlight v-beauty />
</div>
</div>
</div>
Expand Down
89 changes: 89 additions & 0 deletions composables/useDom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2023, Terwer . All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Terwer designates this
* particular file as subject to the "Classpath" exception as provided
* by Terwer in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Terwer, Shenzhen, Guangdong, China, youweics@163.com
* or visit www.terwer.space if you need additional information or have any
* questions.
*/

import * as cheerio from "cheerio"
import { createAppLogger } from "~/common/appLogger"
import { Cheerio } from "cheerio"

/**
* DOM 相关操作钩子
*/
export const useDom = () => {
const logger = createAppLogger("use-dom")

/**
* 获取HTML代码中第一个<img>元素的src属性值
*
* @param {string} html - HTML代码
* @returns {string} 第一个<img>元素的src属性值,如果不存在则返回空字符串
*/
const getFirstImageSrc = (html: string): string => {
logger.info(`getFirstImageSrc called with argument ${html}`) // 记录日志

// 使用 cheerio 加载 HTML 代码
const $ = cheerio.load(html)

// 获取第一个<img>元素
const firstImg = $("img").first()
if (!firstImg.length) {
// 没有找到<img>元素,返回空字符串
return ""
}

// 返回<img>元素的src属性
const src = firstImg.attr("src") || ""
logger.info(`getFirstImageSrc returns ${src}`) // 记录日志
return src
}

/**
* 在 HTML 中添加资源路径前缀
*
* @param {string} html - HTML 代码
* @returns {string} 添加前缀后的 HTML 代码
*/
const addAssetsPrefix = (html: string): string => {
const env = useRuntimeConfig()
const imagePrefix = env.public.siyuanApiUrl
logger.debug("imagePrefix=>", imagePrefix)

// 使用 cheerio 加载 HTML 代码
const $ = cheerio.load(html)
const images = $("img")
for (const image of images) {
const src = image.attribs["src"]
const newImageUrl = [imagePrefix, src].join("/")
logger.debug("image src=>", src)
logger.debug("newImageUrl=>", newImageUrl)

image.attribs["src"] = newImageUrl
}

// 将修改后的 DOM 结构重新序列化成字符串并返回
return $.html()
}

return { getFirstImageSrc, addAssetsPrefix }
}
1 change: 1 addition & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default defineNuxtConfig({
define: {
"process.env.DEV_MODE": `"${isDev}"`,
"process.env.APP_BASE": `"${appBase}"`,
"process.env.SSR": `"false"`,
},
plugins: [],
},
Expand Down
5 changes: 3 additions & 2 deletions nuxt.node.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export default defineNuxtConfig({
define: {
"process.env.DEV_MODE": `"${isDev}"`,
"process.env.APP_BASE": `"${appBase}"`,
"process.env.SSR": `"true"`,
},
plugins: [],
},
Expand Down Expand Up @@ -95,8 +96,8 @@ export default defineNuxtConfig({
runtimeConfig: {
siyuanAuthToken: process.env.NUXT_SIYUAN_AUTH_TOKEN,
public: {
defaultType: process.env.NUXT_PUBLIC_DEFAULT_TYPE,
siyuanApiUrl: process.env.NUXT_PUBLIC_SIYUAN_API_URL,
defaultType: process.env.NUXT_PUBLIC_DEFAULT_TYPE ?? "siyuan",
siyuanApiUrl: process.env.NUXT_PUBLIC_SIYUAN_API_URL ?? "http://127.0.0.1:6806",
waitTime: process.env.NUXT_PUBLIC_WAIT_TIME,
},
},
Expand Down
1 change: 1 addition & 0 deletions nuxt.siyuan.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default defineNuxtConfig({
define: {
"process.env.DEV_MODE": `"${isDev}"`,
"process.env.APP_BASE": `"${appBase}"`,
"process.env.SSR": `"false"`,
},
plugins: [],
},
Expand Down
1 change: 1 addition & 0 deletions nuxt.vercel.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export default defineNuxtConfig({
define: {
"process.env.DEV_MODE": `"${isDev}"`,
"process.env.APP_BASE": `"${appBase}"`,
"process.env.SSR": `"true"`,
},
plugins: [],
},
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"esbuild-style-plugin": "^1.6.2",
"minimist": "^1.2.8",
"nuxt": "^3.5.3",
"sass": "^1.63.4",
"sass": "^1.63.5",
"siyuan": "^0.7.4",
"stylus": "^0.59.0",
"typescript": "^5.1.3"
Expand All @@ -48,6 +48,6 @@
"highlight.js": "^11.8.0",
"pinia": "^2.1.4",
"zhi-device": "^2.3.0",
"zhi-siyuan-api": "^1.21.0"
"zhi-siyuan-api": "^1.22.0"
}
}
7 changes: 4 additions & 3 deletions plugins/01.hljs.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,25 @@ import { useHljs } from "~/plugins/hljs/useHljs"
* @since 0.0.1
*/
export default defineNuxtPlugin(({ vueApp }) => {
const logger = createAppLogger("hljs-plugin")
const logger = createAppLogger("hljs-client-plugin")
const { hljs } = useHljs()
const env = useRuntimeConfig()
logger.info("hljs plugin load")

vueApp.directive("highlight", {
mounted(el, binding) {
const w = Number(env.public.waitTime ?? "500")
setTimeout(() => {
const blocks = el.querySelectorAll("pre code")
Array.prototype.forEach.call(blocks, hljs.highlightBlock)
logger.info("hljs code highlighted")
}, env.public.waitTime ?? 500)
}, w)

setTimeout(() => {
const blocks = el.querySelectorAll("div[class='hljs']")
Array.prototype.forEach.call(blocks, hljs.highlightBlock)
logger.info("hljs div highlighted")
}, env.public.waitTime ?? 500)
}, w)
},
})
})
66 changes: 66 additions & 0 deletions plugins/03.renderer.client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2023, Terwer . All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Terwer designates this
* particular file as subject to the "Classpath" exception as provided
* by Terwer in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Terwer, Shenzhen, Guangdong, China, youweics@163.com
* or visit www.terwer.space if you need additional information or have any
* questions.
*/

import { createAppLogger } from "~/common/appLogger"
import { StrUtil } from "zhi-common"

/**
* 页面渲染插件(图片、链接、公式等) - 客户端
* https://github.com/nuxt/nuxt/issues/13382
* client = browser only
*
* @author terwer
* @version 1.0.0
* @since 0.0.1
*/
export default defineNuxtPlugin(({ vueApp }) => {
const logger = createAppLogger("renderer-client-plugin")

vueApp.directive("beauty", (el: HTMLElement) => {
if (process.env.SSR === "true") {
logger.warn("SSR is enabled, render is dealed with nitro, so the client conversion is ignored")
return
}

logger.info("render:html Start dealing with resource images on client", el)
// assets
const imgs = el.querySelectorAll("img")
if (imgs && imgs.length > 0) {
imgs.forEach((img) => {
const src = img.getAttribute("src") ?? ""
if (src.indexOf("assets") > -1) {
const env = useRuntimeConfig()
const imagePrefix = env.public.siyuanApiUrl
const origin = window.location.origin
const baseUrl = StrUtil.isEmptyString(imagePrefix) ? origin : imagePrefix
const imgUrl = [baseUrl, src].join("/")

img.setAttribute("src", imgUrl)
}
})
logger.info("The local image has been processed and the picture display has been repaired.")
}
})
})
32 changes: 32 additions & 0 deletions plugins/04.render.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2023, Terwer . All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Terwer designates this
* particular file as subject to the "Classpath" exception as provided
* by Terwer in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Terwer, Shenzhen, Guangdong, China, youweics@163.com
* or visit www.terwer.space if you need additional information or have any
* questions.
*/

import { createAppLogger } from "~/common/appLogger"
import { useHljs } from "~/plugins/hljs/useHljs"

// stub - block nuxt getSSRProps error
export default defineNuxtPlugin(({ vueApp }) => {
vueApp.directive("beauty", {})
})
Loading

0 comments on commit a9a8a0d

Please sign in to comment.