-
Notifications
You must be signed in to change notification settings - Fork 317
/
code.ts
156 lines (126 loc) Β· 5.38 KB
/
code.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// This plugin will find all stamps close to a sticky and generate a tally of
// all the stamps (votes) next to a sticky on the page
// This file holds the main code for the plugins. It has access to the *document*.
// You can access browser APIs such as the network by creating a UI which contains
// a full browser environment (see documentation).
// Declare an array of stickies
let stickies: SceneNode[] = [];
let stamps: SceneNode[] = [];
void initialize();
async function initialize() {
// Find all stamps on the page
await figma.loadAllPagesAsync();
stamps = figma.currentPage.findAll(node => node.type === "STAMP");
// If there is a selection, use that
if(figma.currentPage.selection.length > 0){
stickies = figma.currentPage.selection.filter(node => node.type === "STICKY");
// If there is no selection, use all stickies
} else {
stickies = figma.currentPage.findChildren(node => node.type === "STICKY");
}
if(stickies.length > 0){
// Tally up each sticky's votes
Promise.all(stickies.map(sticky => tallyStickyVotes(sticky))).then(() => {
// Notify the user
figma.notify(`Tallied ${stickies.length} ${stickies.length > 1? 'votes' : 'vote' }.`);
figma.closePlugin();
}).catch(() => {
figma.closePlugin();
});
} else {
figma.notify(`No votes found. Add some!`);
// Make sure to close the plugin when you're done. Otherwise the plugin will
// keep running, which shows the cancel button at the bottom of the screen.
figma.closePlugin();
}
}
function isWithinProximity(node1, node2, tolerance = 40){
const node1Center = {x: node1.x + node1.width/2, y: node1.y + node1.height/2};
const node2Center = {x: node2.x + node2.width/2, y: node2.y + node2.height/2};
const proximity = node1.width/2 + tolerance;
return Math.abs(node1Center.x - node2Center.x) <= proximity && Math.abs(node1Center.y - node2Center.y) <= proximity;
}
// Find all votes (stamps) attributed to a sticky (by proximity)
function getStampsNearNode(sticky){
const stampGroups = {};
stamps.forEach(stamp => {
if( isWithinProximity(sticky,stamp,60) ){
if(!stampGroups[stamp.name]){
stampGroups[stamp.name] = [];
}
stampGroups[stamp.name].push(stamp);
}
});
return stampGroups;
}
// Tally all the votes and arrange them in a consumable way
async function tallyStickyVotes(sticky, removeStamps = false){
const stampVotes = getStampsNearNode(sticky);
// Before setting the characters of the tally's text, we need to load the default font
await figma.loadFontAsync({family: "Inter", style: "Medium"});
// Create an Auto Layout frame to hold the tally
const tallyFrame = figma.createFrame();
tallyFrame.cornerRadius = 8;
tallyFrame.resize(128,128);
tallyFrame.layoutMode = "VERTICAL";
tallyFrame.paddingLeft = tallyFrame.paddingRight = tallyFrame.paddingTop = tallyFrame.paddingBottom = 16;
tallyFrame.itemSpacing = 8;
tallyFrame.primaryAxisSizingMode = tallyFrame.counterAxisSizingMode = "AUTO";
tallyFrame.fills = [{type : "SOLID", color: { r: 1, g: 1, b: 1 }}];
tallyFrame.x = sticky.x + sticky.width + 20;
tallyFrame.y = sticky.y;
tallyFrame.strokes = [{type : "SOLID", color: { r: 0, g: 0, b: 0 }}];
tallyFrame.strokeWeight = 2;
tallyFrame.primaryAxisAlignItems = tallyFrame.counterAxisAlignItems = "CENTER";
const tallyTitle = figma.createText();
tallyFrame.appendChild(tallyTitle);
tallyTitle.characters = "Votes";
tallyTitle.textAutoResize = "HEIGHT";
tallyTitle.layoutAlign = "INHERIT";
tallyTitle.textAlignHorizontal = "CENTER";
// Sort all votes to show the highest votes first
const sortedVotes = Object.keys(stampVotes)
.sort((a,b) => {
return stampVotes[b].length - stampVotes[a].length;
});
// Render each stamp with the number of times it was used
sortedVotes.forEach(stampName => {
const tallyLine = figma.createFrame();
tallyFrame.appendChild(tallyLine);
tallyLine.layoutMode = "HORIZONTAL";
tallyLine.itemSpacing = 8;
tallyLine.layoutAlign = "STRETCH";
tallyLine.primaryAxisAlignItems = "MIN";
tallyLine.counterAxisAlignItems = "CENTER";
tallyLine.counterAxisSizingMode = "AUTO";
tallyLine.primaryAxisSizingMode = "AUTO";
tallyLine.clipsContent = false;
// If the vote was a profile, show each profile stamp...otherwise, just show a single stamp
const stampsToShow = stampName === "Profile"? stampVotes[stampName] : [stampVotes[stampName][0]];
const stampFrame = figma.createFrame();
tallyLine.appendChild(stampFrame);
stampFrame.layoutMode = "HORIZONTAL";
stampFrame.itemSpacing = 0;
stampFrame.layoutAlign = "MIN";
stampFrame.primaryAxisAlignItems = "SPACE_BETWEEN";
stampFrame.counterAxisAlignItems = "CENTER";
stampFrame.primaryAxisSizingMode = "FIXED";
stampFrame.clipsContent = false;
stampFrame.resize(stampsToShow.length * 32 * 0.66 ,32);
stampsToShow.forEach(currentStamp => {
const stamp = currentStamp.clone();
stamp.rotation = 0;
stamp.resize(32,32);
stampFrame.appendChild(stamp);
});
const tally = figma.createText();
tallyLine.appendChild(tally);
tally.characters = `${stampVotes[stampName].length}`;
tally.textAutoResize = "HEIGHT";
tally.layoutAlign = "INHERIT";
// Clear the stamps if removeStamps is set to true
if(removeStamps){
stampVotes[stampName].forEach(stamp => stamp.remove())
}
});
}