Skip to content

Instantly share code, notes, and snippets.

@hiloki
Created November 23, 2024 04:50
Show Gist options
  • Save hiloki/e2b767d4ff3e77147861d85a04c9e1de to your computer and use it in GitHub Desktop.
Save hiloki/e2b767d4ff3e77147861d85a04c9e1de to your computer and use it in GitHub Desktop.
const jsonUrl = "https://YOUR_JSON/";
// 下記のような構造のJSONを返すものを用意すると実行できる
// https://jsonbin.io/
//
// [
// {
// "image": "https://image.example.com/xxx.jpg",
// "title": "犬のしつけを成功させる5つの秘訣",
// "description": "犬のしつけは飼い主の一貫した努力が重要です。この記事では、初心者でも簡単に始められるしつけ方法を5つのステップに分けて詳しく解説します。",
// "author": "田中太郎",
// "createAt": "2024-11-23T09:00:00Z"
// },
// {
// "image": "https://image.example.com/xxx.jpg",
// "title": "初心者におすすめの犬種トップ10",
// "description": "初めて犬を飼う人にぴったりの犬種を10種類厳選しました。それぞれの性格や飼いやすさを比較し、あなたに合ったパートナーを見つけるお手伝いをします。",
// "author": "山田花子",
// "createAt": "2024-11-22T15:30:00Z"
// },
// {
// "image": "https://image.example.com/xxx.jpg",
// "title": "健康を守る!犬の食事ガイド",
// "description": "愛犬の健康を維持するためには、適切な食事選びが欠かせません。この記事では、ドッグフードの種類や選び方、注意点について詳しく解説します。",
// "author": "佐藤健",
// "createAt": "2024-11-20T08:45:00Z"
// },
// {
// "image": "https://image.example.com/xxx.jpg",
// "title": "散歩の楽しみ方:犬と一緒に運動不足を解消",
// "description": "毎日の散歩は犬の健康にとって重要なだけでなく、飼い主にとっても良い運動になります。おすすめの散歩コースや犬との遊び方を提案します。",
// "author": "中村美咲",
// "createAt": "2024-11-19T17:00:00Z"
// },
// {
// "image": "https://image.example.com/xxx.jpg",
// "title": "犬の健康管理:動物病院への通い方",
// "description": "愛犬の健康を守るためには、日頃のケアと定期的な動物病院での検診が不可欠です。この記事では、病院に通う際のポイントや準備方法を詳しく紹介します。",
// "author": "高橋一郎",
// "createAt": "2024-11-18T10:15:00Z"
// },
// {
// "image": "https://images.dog.ceo//breeds//shiba//mamehiko01.jpg",
// "title": "子犬の社会化トレーニングのコツ",
// "description": "子犬の社会化は、成犬になったときの性格形成に大きな影響を与えます。他の犬や人間と良好な関係を築くために必要なトレーニング方法をお伝えします。",
// "author": "石田玲奈",
// "createAt": "2024-11-17T13:40:00Z"
// }
// ]
// 再帰的に特定の名前のレイヤーを見つける関数
function findAllNodesByName(node, name, result = []) {
if (node.name === name) {
result.push(node);
}
if ("children" in node) {
node.children.forEach((child) => findAllNodesByName(child, name, result));
}
return result;
}
// 選択されたコンポーネントを取得
const selection = figma.currentPage.selection;
if (selection.length === 1 && selection[0].type === "COMPONENT") {
const component = selection[0]; // コンポーネントを取得
// JSONデータを取得
fetch(jsonUrl)
.then((response) => {
if (!response.ok) {
throw new Error("JSONデータの取得に失敗しました");
}
return response.json();
})
.then((data) => {
const articles = data.record; // JSONの内容を取得
if (!Array.isArray(articles) || articles.length === 0) {
throw new Error("記事データが空です");
}
// Auto Layoutが適用されたフレームを作成
const autoLayoutFrame = figma.createFrame();
autoLayoutFrame.name = "Articles";
autoLayoutFrame.layoutMode = "HORIZONTAL";
autoLayoutFrame.layoutWrap = "WRAP";
autoLayoutFrame.paddingTop = 16;
autoLayoutFrame.paddingBottom = 16;
autoLayoutFrame.paddingLeft = 16;
autoLayoutFrame.paddingRight = 16;
autoLayoutFrame.itemSpacing = 16;
autoLayoutFrame.counterAxisSpacing = 16;
autoLayoutFrame.backgrounds = [];
autoLayoutFrame.resize(1024, 1024);
autoLayoutFrame.primaryAxisSizingMode = "FIXED";
autoLayoutFrame.counterAxisSizingMode = "AUTO"; // 高さをHugに設定
autoLayoutFrame.x = figma.viewport.center.x - autoLayoutFrame.width / 2;
autoLayoutFrame.y = figma.viewport.center.y - autoLayoutFrame.height / 2;
// 記事データごとにインスタンスを生成
const articlePromises = articles.slice(0, 6).map((article) => {
const instance = component.createInstance();
autoLayoutFrame.appendChild(instance);
const imageUpdates = [];
const fontLoads = [];
["Image", "Title", "Description", "Author", "CreateAt"].forEach(
(name) => {
const targetNodes = findAllNodesByName(instance, name);
targetNodes.forEach((node) => {
switch (name) {
case "Image":
// 画像を設定
imageUpdates.push(
fetch(article.image)
.then((res) => res.arrayBuffer())
.then((buffer) => {
const image = figma.createImage(new Uint8Array(buffer));
node.fills = [
{
type: "IMAGE",
scaleMode: "FILL",
imageHash: image.hash,
},
];
})
.catch((err) => console.error("画像の取得に失敗:", err))
);
break;
default:
if (node.type === "TEXT") {
console.log(node.fontName);
// テキストレイヤーのフォントをロード
fontLoads.push(
figma.loadFontAsync(node.fontName).then(() => {
switch (name) {
case "Title":
node.characters = article.title || "";
break;
case "Description":
node.characters = article.description || "";
break;
case "Author":
node.characters = article.author || "";
break;
case "CreateAt":
node.characters =
new Date(article.createAt).toLocaleString() || "";
break;
}
})
);
}
}
});
}
);
return Promise.all([...imageUpdates, ...fontLoads]);
});
return Promise.all(articlePromises).then(() => {
figma.currentPage.appendChild(autoLayoutFrame);
figma.notify("6つの記事データを含むインスタンスを生成しました!");
});
})
.catch((error) => {
console.error("エラー:", error); // デバッグ用
figma.notify("データの取得中にエラーが発生しました: " + error.message);
});
} else {
figma.notify(
"カード型の記事アイテム(コンポーネント)を1つ選択してください。"
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment