Created
November 23, 2024 04:50
-
-
Save hiloki/e2b767d4ff3e77147861d85a04c9e1de to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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