Typecho プログラムを使用してブログを構築する際、一般的に OwO ライブラリ を使用してブログに絵文字機能を提供します。次のように:
OwO ライブラリが提供する統合方法は、従来のフロントエンド開発モデルにより適していますが、現在の Shiro オープンソース版のテーマは NextJS フレームワークに基づいて開発されており、直接テーマに統合するのには適していません。したがって、簡略版の絵文字を自分で開発する必要があります。
絵文字データファイルの作成#
OwO では、絵文字データは OwO.json
ファイルから取得されます。Shiro テーマの場合、src/lib
ディレクトリに owo.ts
ファイルを作成して絵文字データを定義できます。このファイル内で、owo
オブジェクトを作成し、その内容を OwO.json
の構造と一致させて、以前の Typecho テーマの絵文字データを継承できるようにします。
export const owo = {
顔文字: {
type: "emoticon",
container: [
{
icon: 'OωO',
text: 'OωO',
},
//...
],
},
絵文字: {
type: "emoji",
container: [
{
icon: '😂',
text: '喜びの涙を流す顔',
},
//...
],
},
画像絵文字: {
type: "image",
container: [
{
icon: "https://raw.githubusercontent.com/url8/CDN-EMOTE/main/2233/chijing.png",
text: "face1",
},
//...
],
},
};
絵文字ボタンの追加#
Shiro テーマでは、絵文字選択器として Emoji Picker ライブラリを使用しています。
しかし、私のコンピュータでこの選択器をスライドさせるとフレーム落ちが発生するため、自分で作成した絵文字選択器コンポーネントで Emoji Picker を直接置き換えることにしました。
1. カスタム絵文字選択器コンポーネントをインポート:
まず、src\components\modules\comment\CommentBox\UniversalTextArea.tsx
で、元の EmojiPicker
コンポーネントを自分の絵文字選択器コンポーネント Stickers
に置き換えます:
const Stickers = dynamic(() =>
import('../../shared/Stickers').then((mod) => mod.Stickers),
)
2. 既存の EmojiPicker コンポーネントを置き換え:
UniversalTextArea
コンポーネントの返り値の <EmojiPicker onEmojiSelect={handleInsertEmoji} />
を <Stickers handleInsertEmoji={handleInsertEmoji} />
に置き換えます:
return (
<TextArea
bordered={false}
wrapperClassName={className}
ref={taRef}
defaultValue={value}
onKeyDown={handleKeyDown}
onChange={(e) => setter('text', e.target.value)}
placeholder={placeholder}
onCmdEnter={(e) => {
e.preventDefault()
sendComment()
}}
>
<CommentBoxSlotPortal>
<>
{/* {!isMobile && (
<FloatPopover
mobileAsSheet
trigger="click"
TriggerComponent={EmojiButton}
headless
popoverClassNames="pointer-events-auto"
>
<EmojiPicker onEmojiSelect={handleInsertEmoji} />
</FloatPopover>
)} */}
<FloatPopover
mobileAsSheet
trigger="click"
TriggerComponent={EmojiButton}
headless
popoverClassNames="pointer-events-auto shadow-perfect relative z-[2] rounded-xl border border-zinc-400/20 bg-white/80 p-4 outline-none backdrop-blur-lg dark:border-zinc-500/30 dark:bg-neutral-900/80 max-w-lg"
>
<Stickers handleInsertEmoji={handleInsertEmoji} />
</FloatPopover>
</>
</CommentBoxSlotPortal>
</TextArea>
)
3. 絵文字ボタンを変更:
最後に、テキストボックスの左下隅にある絵文字ボタンを変更します:
const EmojiButton = () => {
return (
<div className="ml-4 text-base md:text-xs" role="button" tabIndex={0}>
<span>OwO</span>
</div>
)
}
これで、コメントエリアのテキストボックスの変更が完了しました。
絵文字選択器コンポーネント#
次に、先ほどインポートした絵文字選択器コンポーネント Stickers
を作成する必要があります。このコンポーネントは、絵文字選択器をレンダリングし、ユーザーのクリックイベントを処理します。
src\components\modules\shared
ディレクトリに移動し、Stickers.tsx
という新しいファイルを作成します。
コンポーネント内部では、useState
を使用して現在の絵文字カテゴリ currentCategory
(つまり 顔文字
、 絵文字
またはその他のカテゴリ)を管理し、useMemo
を使用して絵文字カテゴリと現在選択されている絵文字データをキャッシュします。
注意が必要なのは、顔文字の長さが異なることを考慮し、現在の絵文字パッケージが 顔文字
の場合は Grid レイアウトで要素を整列させる必要があることです:
<div
className={`max-h-80 gap-4 overflow-x-hidden overflow-y-scroll pb-4 md:pb-0 ${
currentCategory === '顔文字'
? 'grid grid-cols-4'
: 'flex flex-wrap'
}`}
>
{ ... }
</div>
そうしないと、以下のように不揃いになります:
Stickers.tsx
の完全なコードは以下の通りです:
import { memo, useCallback, useMemo, useState } from 'react'
import type { FC } from 'react'
import { owo } from '~/lib/owo'
type EmojisType = typeof owo
type CategoryKey = keyof EmojisType
export const Stickers: FC<{
handleInsertEmoji: (emoji: string) => void
}> = memo(({ handleInsertEmoji }) => {
const [currentCategory, setCurrentCategory] = useState<CategoryKey>('顔文字')
const emojis: EmojisType = owo
const handleClickEmoji = useCallback(
(emoji: { icon: string; text: any }) => {
if (emoji.icon.startsWith('http')) {
handleInsertEmoji(``)
} else {
handleInsertEmoji(emoji.icon)
}
},
[handleInsertEmoji],
)
const categories = useMemo(
() => Object.keys(emojis) as CategoryKey[],
[emojis],
)
const currentEmojis = useMemo(
() => emojis[currentCategory]?.container || [],
[emojis, currentCategory],
)
return (
<>
{emojis ? (
<>
<div className="mb-2 flex flex-wrap gap-4 text-xs">
{categories.map((category) => (
<button
key={category}
className={`rounded-md px-2 py-1 ${
currentCategory === category ? 'text-accent' : 'opacity-50'
}`}
onClick={() => setCurrentCategory(category)}
>
{category}
</button>
))}
</div>
<div
className={`max-h-80 gap-4 overflow-x-hidden overflow-y-scroll pb-4 md:pb-0 ${
currentCategory === '顔文字'
? 'grid grid-cols-4'
: 'flex flex-wrap'
}`}
>
{currentEmojis.map((item: { icon: string; text: string }) => (
<button
key={item.text}
title={item.text}
onClick={() => handleClickEmoji(item)}
style={{
backgroundImage: item.icon.startsWith('http')
? `url(${item.icon})`
: '',
}}
className={
item.icon.startsWith('http')
? 'h-10 w-10 bg-cover bg-center bg-no-repeat'
: ''
}
>
{!item.icon.startsWith('http') && item.icon}
</button>
))}
</div>
</>
) : (
<div>絵文字を読み込み中...</div>
)}
</>
)
})
Stickers.displayName = 'Stickers'
最後に、プロジェクトを再構築するだけで、Shiro で絵文字機能を使用できるようになります😊。
この記事は Mix Space によって xLog に同期更新されました。元のリンクは https://www.vinking.top/posts/codes/integrating-stickers-into-shiro-theme