SumikaNya

SumikaNya

Shiro テーマのいくつかの変更

前言#

こちらでは現在使用しているテーマにいくつかの小さな変更を加え、その内容を記録しています。皆さんの助けになれば幸いです || もし間違っているところがあれば、積極的に議論してください。私は初心者です ||

Warning

提示
変更部分はあくまで個人の好みですので、異なる意見があればコメント欄で議論してください。

修改顶部导航栏信息展示#

関連ファイルのパスは src\componets\layout\header\config.ts
ファイル内の headerMenuConfig でナビゲーションバーの表示と順序を定義していますので、自分で変更してください。
例えば、ここでは友リンクを二次から移動しました。
image
image

优化高度过长的图片显示时的页面效果#

画像の高さが過剰に長い場合、ページ全体を占めてしまい、閲覧時に一面が画像で埋まってしまうことがあります。過剰に高い画像の表示は良くありませんので、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}
画像がページ全体を占めている
70% の制限が追加された効果
:::

增强 alert 组件,支持自定义 title#

Shiro 拡張の Markdown 構文に GitHub アラートが追加されましたが、タイトルの表示は NOTE、IMPORTANT、WARNING、TIP、CAUTION のみに制限されています。
私は Obsidian を使用して Markdown ファイルを編集しており、その中のアラートはカスタムタイトルスタイルをサポートしています。構文は以下の通りです。

> [!WARNING] 任意のタイトルテキスト
> その他のテキスト内容

2025.7.8 の更新で、innei さんがブロック引用とアラートの処理を更新し、従来の方法は廃止されました!
そこで 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>  
  )  
}

以下为历史处理

この部分の正規表現と解析を修正し、カスタムタイトルの表示を強化しました。ファイルパスは 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があれば取得、なければ従来通り

  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]
 * > ユーザーが考慮すべき情報を強調表示します。
 */
const ALERT_BLOCKQUOTE_R =
  /^(> \[!(?<type>NOTE|IMPORTANT|WARNING|TIP|CAUTION)\](?<title>.*?))(?<body>(?:\n *>.*)*)(?=\n{2,}|$)/ //正規表現を修正し、タイトルの取得を追加

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 //タイトルを追加
    let first = true //置換の論理を制御するため、最初の行は>を除去し、他の行は<br>に置換
    const bodyClean = body.replace(/^> */gm, (match: string) => first ? (first = false, '') : '<br>').trim() //置換ロジックを修正

    return (
      <blockquote
        className={clsx(borderColorMap[type], 'not-italic')}
        key={state.key}
      >
        <!--タイトル解析を追加し、改行ロジックを調整-->
        <AlertIcon type={type as any} title={title} /> 
        

        <Markdown
          allowsScript
          className="not-prose w-full [&>p:first-child]:mt-0"
        >
          {bodyClean}
        </Markdown>
      </blockquote>
    )
  },
}

修正後は以下の効果を実現できます。複数のアラートが並ぶ場合は、間に <div /> を挟むことを忘れないでください。

> [!WARNING] 任意のタイトルテキスト
> その他のテキスト内容

> [!NOTE] 任意のタイトルテキスト
> その他のテキスト内容

Warning

任意のタイトルテキスト
その他のテキスト内容

Note

任意のタイトルテキスト
その他のテキスト内容

この記事は Mix Space によって xLog に同期更新されました。
元のリンクは https://blog.lolita.best/posts/blog/ShiroModifySumika


読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。