Skip to content

Commit 24c24d4

Browse files
authored
Merge pull request #306 from hunghg255/feature/image-gif-tenor
2 parents 6f6f1d7 + 72c367a commit 24c24d4

File tree

5 files changed

+647
-48
lines changed

5 files changed

+647
-48
lines changed

docs/extensions/ImageGif/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ const extensions = [
1919
...,
2020
// Import Extensions Here
2121
ImageGif.configure({// [!code ++]
22-
GIPHY_API_KEY: 'GIPHY_API_KEY', // [!code ++]
22+
API_KEY: '', // [!code ++]
23+
provider: 'tenor' // [!code ++] (tenor or giphy)
2324
}),// [!code ++]
2425
];
2526
```
2627

27-
- `GIPHY_API_KEY` - Giphy API Key. You can get it from [Giphy Developers](https://developers.giphy.com/).
28+
- `API_KEY` - You can get it from [Giphy Developers](https://developers.giphy.com/) or [Tenor Developers](https://tenor.com/)

playground/src/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ const extensions = [
133133
},
134134
}),
135135
ImageGif.configure({
136-
GIPHY_API_KEY: import.meta.env.VITE_GIPHY_API_KEY as string,
136+
provider: 'giphy',
137+
API_KEY: import.meta.env.VITE_GIPHY_API_KEY as string
137138
}),
138139
Blockquote,
139140
SlashCommand,

src/extensions/ImageGif/ImageGif.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ export interface SetImageAttrsOptions {
1919
}
2020

2121
interface ImageGifOptions extends ImageOptions {
22+
provider: 'giphy' | 'tenor'
2223
/**
23-
* The key for the gif https://giphy.com/
24+
* The key for the gif https://giphy.com/ or https://tenor.com/
2425
*/
25-
GIPHY_API_KEY: string
26+
API_KEY: string
2627
}
2728

2829
declare module '@tiptap/core' {
@@ -53,12 +54,14 @@ export const ImageGif = /* @__PURE__ */ TiptapImage.extend<ImageGifOptions>({
5354
content: '',
5455
marks: '',
5556
group: 'block',
56-
GIPHY_API_KEY: '',
57+
API_KEY: '',
58+
provider: 'giphy',
5759
draggable: false,
5860
selectable: true,
5961
atom: true,
6062
button: ({ editor, extension, t }: any) => {
61-
const giphyApiKey = extension?.options?.GIPHY_API_KEY || '';
63+
const provider = extension?.options?.provider || '';
64+
const apiKey = extension?.options?.API_KEY || '';
6265

6366
return {
6467
component: ImageGifActionButton,
@@ -71,7 +74,8 @@ export const ImageGif = /* @__PURE__ */ TiptapImage.extend<ImageGifOptions>({
7174
disabled: false,
7275
icon: 'GifIcon',
7376
tooltip: t('editor.imageGif.tooltip'),
74-
giphyApiKey,
77+
apiKey,
78+
provider
7579
},
7680
};
7781
},

src/extensions/ImageGif/components/ImageGifActionButton.tsx

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,53 +4,76 @@ import { useCallback, useEffect, useRef, useState } from 'react';
44
import { debounce } from 'lodash-es';
55

66
import { ActionButton, Input, Popover, PopoverContent, PopoverTrigger } from '@/components';
7+
import { type GifItem, serviceGetTrendingGiphy, serviceGetTrendingTenor, serviceSearchGiphy, serviceSearchTenor } from '@/extensions/ImageGif/components/services';
78

89
interface IProps {
910
showClear?: boolean
1011
selectImage: (arg: string) => void
1112
children: React.ReactNode
12-
giphyApiKey: string
13+
apiKey: string
14+
provider: string;
1315
}
1416

15-
function ImageGifWrap({ selectImage, giphyApiKey, children }: IProps) {
16-
const [gifs, setGifs] = useState([]);
17-
const [limit] = useState(15);
17+
function useServiceGif (provider: string, apiKey: string) {
1818

19-
const inputRef = useRef(null);
19+
const searchTrending = async (): Promise<GifItem[]> => {
20+
if (!apiKey) return [];
21+
22+
if (provider === 'giphy') {
23+
return serviceGetTrendingGiphy(apiKey);
24+
}
2025

21-
const search = (term: any, kind: any = 'search') => {
22-
if (!giphyApiKey) {
23-
return;
26+
if (provider === 'tenor') {
27+
return serviceGetTrendingTenor(apiKey);
2428
}
2529

26-
const url
27-
= kind === 'search'
28-
? `https://api.giphy.com/v1/gifs/search?q=${term}`
29-
: `https://api.giphy.com/v1/gifs/trending?q=${term}`;
30-
const link = `${url}&limit=${limit}&api_key=${giphyApiKey}`;
31-
32-
fetch(link).then(r => r.json()).then((response) => {
33-
// handle success
34-
setGifs(response.data);
35-
})
36-
.catch((error) => {
37-
// handle error
38-
console.log(error);
39-
});
30+
return [];
4031
};
4132

33+
const searchWord = async (word: string): Promise<GifItem[]> => {
34+
if (!apiKey) return [];
35+
36+
if (provider === 'giphy') {
37+
return serviceSearchGiphy(word, apiKey);
38+
}
39+
40+
if (provider === 'tenor') {
41+
return serviceSearchTenor(word, apiKey);
42+
}
43+
44+
return [];
45+
};
46+
47+
return {
48+
searchTrending,
49+
searchWord
50+
};
51+
}
52+
53+
function ImageGifWrap({ selectImage, apiKey, provider, children }: IProps) {
54+
const [gifs, setGifs] = useState<GifItem[]>([]);
55+
56+
const inputRef = useRef(null);
57+
58+
const { searchTrending, searchWord } = useServiceGif(provider, apiKey);
59+
4260
useEffect(() => {
43-
search('', 'trend');
61+
(async () => {
62+
const r = await searchTrending();
63+
setGifs(r);
64+
})();
4465
}, []);
4566

4667
const handleInputChange = useCallback(
47-
debounce((event: React.ChangeEvent<HTMLInputElement>) => {
68+
debounce(async (event: React.ChangeEvent<HTMLInputElement>) => {
4869
if (!event.target.value) {
49-
search('', 'trend');
70+
const r = await searchTrending();
71+
setGifs(r);
5072
return;
5173
}
5274
// Add your logic here
53-
search(event.target.value);
75+
const r = await searchWord(event.target.value);
76+
setGifs(r);
5477
}, 350), // Adjust the debounce delay as needed
5578
[],
5679
);
@@ -68,7 +91,7 @@ function ImageGifWrap({ selectImage, giphyApiKey, children }: IProps) {
6891
>
6992

7093
{
71-
giphyApiKey
94+
apiKey
7295
? (
7396
<>
7497
<div className="richtext-mb-[10px] richtext-w-full">
@@ -84,15 +107,15 @@ function ImageGifWrap({ selectImage, giphyApiKey, children }: IProps) {
84107
<div className="richtext-grid richtext-grid-cols-2 richtext-gap-1 ">
85108

86109
{gifs?.length
87-
? gifs?.map((o: any) => (
110+
? gifs?.map((item) => (
88111
<img
89-
alt="giphy"
112+
alt=''
90113
className="richtext-cursor-pointer richtext-text-center"
91-
height={o.images.fixed_width_downsampled.height}
92-
key={`giphy-${o.id}`}
93-
onClick={() => selectImage(o)}
94-
src={o.images.fixed_width_downsampled.url}
95-
width={o.images.fixed_width_downsampled.width}
114+
height={item.height}
115+
key={item.id}
116+
onClick={() => selectImage(item.src)}
117+
src={item.src}
118+
width={item.width}
96119
/>
97120
))
98121
: <p>
@@ -115,16 +138,15 @@ function ImageGifWrap({ selectImage, giphyApiKey, children }: IProps) {
115138
);
116139
}
117140

118-
export function ImageGifActionButton({ editor, icon, giphyApiKey, ...props }: any) {
119-
const selectImage = (giphyblock: any) => {
120-
const { url } = giphyblock.images.original;
121-
122-
editor.chain().focus().setImageGif({ src: url }).run();
141+
export function ImageGifActionButton({ editor, icon, provider, apiKey, ...props }: any) {
142+
const selectImage = (src: string) => {
143+
editor.chain().focus().setImageGif({ src }).run();
123144
};
124145

125146
return (
126147
<ImageGifWrap
127-
giphyApiKey={giphyApiKey}
148+
apiKey={apiKey}
149+
provider={provider}
128150
selectImage={selectImage}
129151
>
130152
<ActionButton

0 commit comments

Comments
 (0)