前言#
這邊對於當前使用的主題做了一些小修改,記錄一下修改的內容,希望可以幫助到大家 || 如果有地方出錯了,也請積極討論,我是菜雞 ||
Warning
提示
修改部分僅個人喜好,如果有不一樣的想法歡迎在評論區討論
修改頂部導航欄信息展示#
相關文件路徑在 src\componets\layout\header\config.ts
文件中的 headerMenuConfig 中定義了導航欄的顯示與順序,自行修改即可
比如這邊將友鏈移出了二級
優化高度過長的圖片顯示時的頁面效果#
如果圖片高度過長會佔滿整個頁面,可能在瀏覽時一整頁都是圖片,對於過高的圖片顯示效果不好,我們可以通過使用 css 中的 max-height
去限制元素的高度顯示
在 src\components\ui\image\ZoomedImage.tsx
中找到以下部分,並添加 max-height max-h-[70vh] w-auto object-contain
來讓圖片的最大高度不會超過 70% (參數可自行調整),寬度保持自適應,圖片會完整顯示不會被裁剪
const styles = tv({
base: 'rounded-xl overflow-hidden text-center inline-flex items-center justify-center duration-200 max-height max-h-[70vh] w-auto object-contain',
variants: {
status: {
loading: 'hidden opacity-0',
loaded: 'opacity-100 block',
error: 'hidden opacity-0',
},
},
})
::: grid {cols=2,rows=1,gap=4,type=images}
:::
增強 alert 組件,支持自定義 title#
Shiro 擴展的 markdown 語法內增加了 github alert,但是其限制了標題的顯示上只能是 NOTE、IMPORTANT、WARNING、TIP、CAUTION
由於本人使用的是 Obsidian 編輯 Markdown 文件,其中的 alert 可以支持自定義標題樣式,語法如下
> [!WARNING] 任意標題文本
> 其他文本內容
2025.7.8 更新,innei 佬更新了 blockquote 和 alert 的處理,原有方式作廢啦!
於是使用了 Claude 幫忙修改了文件,實現了同樣的效果
src\components\ui\markdown\parsers\blockquote.tsx
import React, { Children, cloneElement, useMemo } from 'react';
import type { FC, ReactNode } from 'react';
import { GitAlert } from './alert';
const getNodeText = (node: ReactNode): string => {
if (node == null) return '';
if (typeof node === 'string' || typeof node === 'number') return node.toString();
if (Array.isArray(node)) return node.map(getNodeText).join('');
if (React.isValidElement<{ children?: ReactNode }>(node)) return getNodeText(node.props.children);
return '';
};
export const MBlockQuote: FC<{
className?: string;
children: ReactNode;
alert?: string;
}> = ({ className, children, alert }) => {
if (alert) return <GitAlert type={alert}>{children}</GitAlert>;
const { isAlert, alertType, title, content } = useMemo(() => {
const childrenArray = Children.toArray(children);
const elementChildren = childrenArray.filter(React.isValidElement);
if (elementChildren.length === 0) return { isAlert: false, alertType: '', title: undefined, content: childrenArray };
const firstChild = elementChildren[0];
const alertMatch = getNodeText(firstChild).trim().match(/^\[!(\w+)\](?:\s(.*))?/);
if (!alertMatch) return { isAlert: false, alertType: '', title: undefined, content: childrenArray };
const alertType = alertMatch[1].toUpperCase();
const customTitle = alertMatch[2]?.trim() || undefined;
const contentNodes: ReactNode[] = [];
if (React.isValidElement<{ children?: ReactNode }>(firstChild)) {
const internalChildren = Children.toArray(firstChild.props.children);
if (internalChildren.length > 0 && typeof internalChildren[0] === 'string') {
const contentOnlyText = internalChildren[0].replace(/^\s*\[!(\w+)\]\s*[^\n]*\n?/, '');
const modifiedFirstChild = cloneElement(firstChild, { key: 'first-child-content' }, contentOnlyText, ...internalChildren.slice(1));
contentNodes.push(modifiedFirstChild);
} else {
contentNodes.push(firstChild);
}
}
contentNodes.push(...elementChildren.slice(1));
return { isAlert: true, alertType, title: customTitle, content: contentNodes };
}, [children]);
if (isAlert) {
return (
<GitAlert type={alertType} title={title}>
{content}
</GitAlert>
);
}
return (
<blockquote className={className}>
{content}
</blockquote>
);
};
src\components\ui\markdown\parsers\alert.tsx
CAUTION: FluentShieldError20Regular,
}
const AlertIcon: FC<{
type: keyof typeof typedIconMap
title?: string
}> = ({ type, title }) => {
const finalType = type || 'NOTE'
const Icon = typedIconMap[finalType] || typedIconMap.NOTE
const typePrefix = title || (finalType[0] + finalType.toLowerCase().slice(1));
return (
<span
@@ -57,9 +58,8 @@ export const AlertIcon: FC<{
)
}
export const GitAlert: FC<{ type: string; title?: string; children: React.ReactNode }> = (props) => {
const { type, title, children } = props
const upperType = type.toUpperCase() as keyof typeof borderColorMap
return (
<blockquote
@@ -71,10 +71,10 @@ export const GitAlert = (props: { type: string; text: string }) => {
'not-italic',
)}
>
<AlertIcon type={upperType as any} title={title} />
<br />
{children}
</blockquote>
)
}
以下為歷史處理
於是對這塊部分的正則與解析進行了修改,增強了可自定義 title 的顯示,文件路徑在 src\components\ui\markdown\parsers\alert.tsx
import clsx from 'clsx'
import type { MarkdownToJSX } from 'markdown-to-jsx'
import { blockRegex, Priority } from 'markdown-to-jsx'
import type { FC } from 'react'
import {
FluentShieldError20Regular,
FluentWarning28Regular,
IonInformation,
} from '~/components/icons/status'
import { Markdown } from '../Markdown'
const textColorMap = {
NOTE: 'text-blue-500 dark:text-blue-400',
IMPORTANT: 'text-accent',
WARNING: 'text-amber-500 dark:text-amber-400',
TIP: 'text-green-500 dark:text-green-400',
CAUTION: 'text-red-500 dark:text-red-400',
} as any
const borderColorMap = {
NOTE: 'before:bg-blue-500 before:bg-blue-400',
IMPORTANT: 'before:bg-accent',
WARNING: 'before:bg-amber-500 dark:before:bg-amber-400',
TIP: 'before:bg-green-500 dark:before:bg-green-400',
CAUTION: 'before:bg-red-500 dark:before:bg-red-400',
} as any
const typedIconMap = {
NOTE: IonInformation,
IMPORTANT: FluentWarning28Regular,
WARNING: FluentShieldError20Regular,
TIP: IonInformation,
CAUTION: FluentShieldError20Regular,
}
export const AlertIcon: FC<{
type: keyof typeof typedIconMap
title?: string //定義title
}> = ({ type, title }) => { //增加title
const finalType = type || 'NOTE'
const Icon = typedIconMap[finalType] || typedIconMap.NOTE
const typePrefix = title || (finalType[0] + finalType.toLowerCase().slice(1)) //如果title有值則獲取title,否則跟之前一樣
return (
<span
className={clsx('mb-1 inline-flex items-center', textColorMap[finalType])}
>
<Icon
className={clsx(
`shrink-0 text-3xl md:mr-2 md:self-start md:text-left`,
typedIconMap[finalType] || typedIconMap.NOTE,
)}
/>
{typePrefix}
</span>
)
}
/**
*
* > [!NOTE]
* > Highlights information that users should take into account, even when skimming.
*/
const ALERT_BLOCKQUOTE_R =
/^(> \[!(?<type>NOTE|IMPORTANT|WARNING|TIP|CAUTION)\](?<title>.*?))(?<body>(?:\n *>.*)*)(?=\n{2,}|$)/ //修改正則表達式,增加title的獲取
export const AlertsRule: MarkdownToJSX.Rule = {
match: blockRegex(ALERT_BLOCKQUOTE_R),
order: Priority.HIGH,
parse(capture) {
return {
raw: capture[0],
parsed: {
...capture.groups,
},
} as any
},
react(node, output, state) {
const { type, body, title } = node.parsed //增加title
let first = true //控制replace的替換邏輯,第一行去除>,其餘行替換為<br>
const bodyClean = body.replace(/^> */gm, (match: string) => first ? (first = false, '') : '<br>').trim() //替換邏輯修改
return (
<blockquote
className={clsx(borderColorMap[type], 'not-italic')}
key={state.key}
>
<!--增加title解析,調整換行邏輯-->
<AlertIcon type={type as any} title={title} />
<Markdown
allowsScript
className="not-prose w-full [&>p:first-child]:mt-0"
>
{bodyClean}
</Markdown>
</blockquote>
)
},
}
修改後就可以實現以下效果,如果有多個 alert 在一起的時候記得中間要用 <div />
隔開
> [!WARNING] 任意標題文本
> 其他文本內容
> [!NOTE] 任意標題文本
> 其他文本內容
Warning
任意標題文本
其他文本內容
Note
任意標題文本
其他文本內容
此文由 Mix Space 同步更新至 xLog
原始鏈接為 https://blog.lolita.best/posts/blog/ShiroModifySumika