Slack の絵文字を FigJam のステッカーにする
こちらはFigma 開発アドベントカレンダー21日目の記事です。
FigJam で会議をしている時
「あ、Slack のあの絵文字押してぇ...!!」ってなることありませんか?私はあります。
というわけで Slack の絵文字を FigJam のステッカーとして読み込むための Widget を作ってみました。
Express でサーバー作る
Figma Widget からでも API リクエストは別に飛ばせるのですが、 Origin が null になってしまうせいか CORS エラーになってしまいました。
Access to fetch at 'https://slack.com/api/emoji.list' from origin 'null' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.
とりあえず今回は自分のローカル環境で動けばいいので、express でサーバーを立てて、そこから Slack API を叩き、Figma からはその express サーバからリクエストを送る方式を取ります。
まずはインストール。
npm install express
そして Hello World
const express = require("express");
const app = express();
const port = 3003;
// CORS ノーガード
const allowCrossDomain = function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
res.header(
"Access-Control-Allow-Headers",
"Content-Type, Authorization, access_token"
);
// intercept OPTIONS method
if ("OPTIONS" === req.method) {
res.send(200);
} else {
next();
}
};
app.use(allowCrossDomain);
app.get("/", async (req, res) => {
// ここに Slack API を叩く処理を書いていくぜ。
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
Slack API から絵文字のデータとってくる
次に Slack の API を叩く手筈を整えます。
まずはトークンを手に入れます。
ここから絵文字を抜き出したいワークスペースに対してアプリを作成してなんやかんや頑張ってトークンをゲットしてください。また、 emoji:read の権限も追加してください。
次に Slack API クライアントをインストールします。
npm install @slack/web-api
そしてこれを使うとこんな感じで簡単にゲットできます。
const { WebClient } = require("@slack/web-api");
const token = "xoxb-で始まるトークン";
app.get("/", async (req, res) => {
const client = new WebClient(token);
const response = await client.emoji.list();
// 中身は {[key as 絵文字の名前]: "絵文字のソース"} というフォーマットです。
res.send(response.emoji);
});
Widget を作る
いよいよ Figma 側です。
本当は API が楽だったのですが、Figma API は Write 系の処理ができないっぽいので Widget を作ります。
まずは npm init @figma/widget
してプロジェクトを作ります。
そして manifest ファイルを読み込み npm run dev でビルドするとこのような無機質な Widget が登場します。
そして code.tsx を開いて下記のような感じで書き換えます。
内容としては先ほど作った API からデータを取ってきて、ひたすらその画像をコンポーネントにしています。
const { widget } = figma;
const {
AutoLayout,
Ellipse,
Frame,
Image,
Rectangle,
SVG,
Text,
useSyncedState,
} = widget;
function Widget() {
const createImage = async (
emojiName: string,
src: string,
rowIndex: number,
colIndex: number
) => {
const imageNode = await figma.createNodeFromJSXAsync(
<Image src={src} width={32} height={32} />
);
const component = figma.createComponent();
component.name = emojiName;
component.appendChild(imageNode);
component.x = 32 * colIndex;
component.y = 32 * rowIndex;
};
const onClick = () => {
fetch("http://localhost:3003", {
method: "GET",
})
.then((response) => response.text())
.then((text) => {
const emojis = JSON.parse(text);
const emojiKeys = Object.keys(emojis);
const chunkSize = 10;
const chunks = [];
const intervalMsec = 2000;
for (let i = 0; i < emojiKeys.length; i += chunkSize) {
chunks.push(
emojiKeys
.slice(i, i + chunkSize)
.map((key) => ({ key, src: emojis[key] }))
);
}
chunks.forEach((chunk, rowIndex) => {
setTimeout(() => {
chunk.forEach((emoji, colIndex) => {
createImage(emoji.key, emoji.src, rowIndex, colIndex);
});
}, intervalMsec * rowIndex);
});
})
.catch((e) => {
console.log(e);
});
};
return (
<AutoLayout
direction="horizontal"
horizontalAlignItems="center"
verticalAlignItems="center"
height="hug-contents"
padding={8}
fill="#FFFFFF"
cornerRadius={8}
spacing={12}
onClick={onClick}
>
<Text fontSize={32} horizontalAlignText="center">
Click Me
</Text>
</AutoLayout>
);
}
widget.register(Widget);
ポイントは chunk に分けて、インターバルを設けて実行しているところです。
なぜそうしているかというと、スタンプが多いと処理がとんでもなく重くなり、Figma をクラッシュさせてしまうからです。時間はかかってしまいますが負荷をかけないようにしていきましょう。
これが無事終了すると絵文字の山ができあがります。
ちなみにスタンプの数が多いとめっちゃファイル重くなります。当然ですね。
ライブラリとして Publish して FigJam から使えるようにする
できたらライブラリとして Publish します!!
そして FigJam の Stickers の Add your own からそのライブラリを作れば準備万端です!!
ちなみにスタンプが多いと初期のロードはエグいもっさりしますが、その後は簡単に検索できてる気がします。
ぜひお気に入りの Slack スタンプたちを FigJam に持ち込んで会議を盛り上げてください!
Discussion