├── .gitignore ├── manifest.json ├── README.md ├── ui.html └── code.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Appearance", 3 | "id": "760927481606931799", 4 | "api": "1.0.0", 5 | "main": "code.js", 6 | "ui": "ui.html", 7 | "menu": [ 8 | {"name": "Dark mode", "command": "dark"}, 9 | {"name": "Light mode", "command": "light"}, 10 | {"separator": true}, 11 | {"name": "Settings", "command": "name_settings_ui"}, 12 | {"name": "Save styles", "command": "get_colors"} 13 | ] 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Appearance. Figma plugin. 2 | 3 | This plugin generates a dark/light mode from your selection. 4 | The plugin works with external library styles and local styles. 5 | You can choose styles name identification in settings. By default, the plugin use [day] for light and [night] for dark. 6 | 7 | [Link to the Figma plugin page](https://www.figma.com/c/plugin/760927481606931799/Appearance) 8 | 9 | image 10 | 11 | ## How it works: 12 | 1. Use a keyword [day] and [night] in your style names. Example: Style name[day]/ Style name[night]. 13 | 2. Apply your color styles. 14 | 3. Select any object, then choose Appearance → Dark mode or Appearance → Light mode. 15 | 16 | ## How it works with external library styles: 17 | 1. Open external library file and use a keyword [day] and [night] in color style names. Example: Style name[day]/ Style name[night]. 18 | 2. Publish changes. 19 | 3. Select Appearance → Save styles for saving external color styles to the plugin. 20 | 4. Open any file linked to the library. 21 | 5. Apply color styles. 22 | 6. Select any object then choose Appearance → Dark mode or Appearance → Light mode 23 | 24 | ## Styles name examples: 25 | You can use [day] / [night] at any place of your style name. 26 | ``` 27 | Color name [day] 28 | Color name [night] 29 | ``` 30 | ``` 31 | Style [day] / color-name 32 | Style [night] / color-name 33 | ``` 34 | ``` 35 | Style / color-name [day] 36 | Style / color-name [night] 37 | ``` 38 | ## How to install in the Dev environment 39 | * Select the Plugins Page in the Figma File Browser 40 | * Use the plus (+) button in the Development section 41 | * Choose file manifest.json 42 | * Done -------------------------------------------------------------------------------- /ui.html: -------------------------------------------------------------------------------- 1 | 2 | 63 | 64 | 65 | 66 | 67 |
68 | Enter dark / light color styles name identificator 69 |
70 |
Light:
71 |
72 |
73 | 74 |
75 |
Dark:
76 |

77 |
78 | 79 | 80 | 81 | 82 | 113 |
114 | 115 | -------------------------------------------------------------------------------- /code.js: -------------------------------------------------------------------------------- 1 | var day = "[day]"; 2 | var night = "[night]"; 3 | var allSelection; 4 | var colorsArray = []; 5 | var counter = 0; 6 | var object = {}; 7 | var objectLocal = {}; 8 | var publicEffectStyles; 9 | var allEffects; 10 | 11 | setNamesToStorage() 12 | async function setNamesToStorage() { 13 | var dayFromStorage = await figma.clientStorage.getAsync('dayFromStorage') 14 | var nightFromStorage = await figma.clientStorage.getAsync('nightFromStorage') 15 | 16 | if (typeof dayFromStorage === 'undefined') { 17 | await figma.clientStorage.setAsync('dayFromStorage', day) 18 | } 19 | if (typeof nightFromStorage === 'undefined') { 20 | await figma.clientStorage.setAsync('nightFromStorage', night) 21 | } 22 | // console.log(dayFromStorage) 23 | } 24 | 25 | // NAME SETTINGS UI 26 | if (figma.command == 'name_settings_ui') { 27 | figma.showUI(__html__, { width: 240, height: 170 }) 28 | 29 | sendToUI() 30 | async function sendToUI() { 31 | 32 | var dayFromStorage = await figma.clientStorage.getAsync('dayFromStorage') 33 | var nightFromStorage = await figma.clientStorage.getAsync('nightFromStorage') 34 | 35 | if (typeof dayFromStorage === 'undefined' || typeof nightFromStorage === 'undefined') { 36 | await figma.clientStorage.setAsync('dayFromStorage', day) 37 | await figma.clientStorage.setAsync('nightFromStorage', night) 38 | } 39 | // console.log(dayFromStorage) 40 | if (dayFromStorage.length > 0 || nightFromStorage.length > 0) { 41 | figma.ui.postMessage({ day: dayFromStorage, night: nightFromStorage }) 42 | } 43 | // figma.ui.postMessage({ day: dayFromStorage, night: nightFromStorage }) 44 | } 45 | 46 | 47 | // Recieving settings from UI 48 | figma.ui.onmessage = async (msg) => { 49 | if (msg.type === 'dayInput') { 50 | await figma.clientStorage.setAsync('dayFromStorage', msg.dayColor) 51 | figma.closePlugin('👌 Settings saved'); 52 | } 53 | if (msg.type === 'nightInput') { 54 | await figma.clientStorage.setAsync('nightFromStorage', msg.nightColor) 55 | } 56 | if (msg.type === 'clearStorage') { 57 | await figma.clientStorage.setAsync('dayFromStorage', day) 58 | await figma.clientStorage.setAsync('nightFromStorage', night) 59 | // await figma.clientStorage.setAsync('dayFromStorage') 60 | // await figma.clientStorage.setAsync('nightFromStorage') 61 | // await figma.clientStorage.setAsync('allColors') 62 | // await figma.clientStorage.setAsync('allEffects') 63 | figma.closePlugin('😶 All settings were reset'); 64 | } 65 | } 66 | } 67 | 68 | // GET LIBRARY COLORS 69 | if (figma.command == 'get_colors') { 70 | 71 | if (figma.getLocalPaintStyles().length == 0){ 72 | figma.closePlugin('😶 This document does not have styles'); 73 | } else { 74 | setPaints() 75 | colorsNumber() 76 | 77 | async function setPaints() { 78 | await figma.clientStorage.setAsync('allColors', figma.getLocalPaintStyles().map(a => a.key)) 79 | await figma.clientStorage.setAsync('allEffects', figma.getLocalEffectStyles().map(a => a.key)) 80 | } 81 | 82 | async function colorsNumber() { 83 | var allColors = await figma.clientStorage.getAsync('allColors') 84 | // console.log(allColors.length) 85 | 86 | if (allColors.length > 0){ 87 | figma.closePlugin(`👌 Styles saved`); 88 | } else { 89 | figma.closePlugin('😶 You don`t have saved styles'); 90 | } 91 | } 92 | } 93 | } 94 | 95 | // SELECTED DARK MODE 96 | if (figma.command == 'dark') { 97 | 98 | async function getPaints() { 99 | var publicColorStyles = await figma.clientStorage.getAsync('allColors'); 100 | var publicEffectStyles = await figma.clientStorage.getAsync('allEffects'); 101 | 102 | if (typeof publicColorStyles === 'undefined') { 103 | await figma.clientStorage.setAsync('allColors', "") 104 | // console.log(publicColorStyles) 105 | } 106 | if (typeof publicEffectStyles === 'undefined') { 107 | await figma.clientStorage.setAsync('allEffects', "") 108 | } else { 109 | var publicStyles = [...publicColorStyles, ...publicEffectStyles] 110 | // console.log(publicColorStyles) 111 | } 112 | 113 | var localColorStyles = figma.getLocalPaintStyles(); 114 | var localEffectStyles = figma.getLocalEffectStyles(); 115 | var localStyles = [...localColorStyles, ...localEffectStyles] 116 | // console.log(localStyles) 117 | 118 | var days = {} 119 | var nights = {} 120 | 121 | // getting identificator words 122 | var dayFromStorage = await figma.clientStorage.getAsync('dayFromStorage') 123 | var nightFromStorage = await figma.clientStorage.getAsync('nightFromStorage') 124 | 125 | if (typeof dayFromStorage === 'undefined') { 126 | dayFromStorage = day; 127 | // console.log(dayFromStorage) 128 | } 129 | 130 | if (typeof publicStyles === 'undefined' && localStyles.length == 0) { 131 | figma.closePlugin('😶 This document does not have styles'); 132 | 133 | } else { 134 | var importStyles = await Promise.all( 135 | publicStyles.map((styleKey) => 136 | figma.importStyleByKeyAsync(styleKey) 137 | .catch(() => {}) 138 | ) 139 | ); 140 | 141 | if (importStyles[0] == undefined) { 142 | // console.log(importStyles) 143 | var importStyles = []; 144 | } 145 | 146 | var allStyles = [...localStyles, ...importStyles] 147 | // console.log(allStyles) 148 | 149 | //Creating style couples 150 | for (let paintStyle of allStyles) { 151 | const name = paintStyle.name 152 | const id = paintStyle.id 153 | if (name.includes(nightFromStorage)) { 154 | const key = name.replace(nightFromStorage, ''); 155 | nights[key] = id; 156 | } else if (name.includes(dayFromStorage)) { 157 | const key = name.replace(dayFromStorage, ''); 158 | days[key] = id; 159 | } 160 | } 161 | 162 | Object.entries(days).forEach(([name, id]) => { 163 | object[id] = nights[name]; 164 | // object[nights[name]] = id; 165 | }); 166 | 167 | Object.entries(days).forEach(([name, id]) => { 168 | objectLocal[id.slice(0,43)] = nights[name]; 169 | }); 170 | } 171 | } 172 | 173 | // Changing colors 174 | function findSelectedFrames() { 175 | if (figma.currentPage.selection.length == 0) { 176 | figma.closePlugin("🤔 No object selected. Please select any object"); 177 | 178 | } else { 179 | try { 180 | var allSelection = figma.currentPage.selection[0].findAll(); 181 | } catch(error) { 182 | var allSelection = []; 183 | } 184 | allSelection.unshift(figma.currentPage.selection[0]); 185 | } 186 | 187 | for (let frame of allSelection) { 188 | if (frame.fillStyleId && object && object[frame.fillStyleId]) { 189 | frame.fillStyleId = object[frame.fillStyleId]; 190 | counter++; 191 | } 192 | if (frame.effectStyleId && object && object[frame.effectStyleId]) { 193 | frame.effectStyleId = object[frame.effectStyleId]; 194 | counter++; 195 | } 196 | if (frame.strokeStyleId && object && object[frame.strokeStyleId]) { 197 | frame.strokeStyleId = object[frame.strokeStyleId]; 198 | counter++; 199 | } 200 | if (frame.fillStyleId && objectLocal && objectLocal[frame.fillStyleId]) { 201 | frame.fillStyleId = objectLocal[frame.fillStyleId]; 202 | counter++; 203 | } 204 | if (frame.effectStyleId && objectLocal && objectLocal[frame.effectStyleId]) { 205 | frame.effectStyleId = objectLocal[frame.effectStyleId]; 206 | counter++; 207 | } 208 | if (frame.strokeStyleId && objectLocal && objectLocal[frame.strokeStyleId]) { 209 | frame.strokeStyleId = objectLocal[frame.strokeStyleId]; 210 | counter++; 211 | } 212 | } 213 | } 214 | //Checking day colors 215 | function notDayObjects() { 216 | if (counter == 0) { 217 | figma.closePlugin(`😶 Selection does not have style pairs`); 218 | } 219 | } 220 | 221 | getPaints().then(() => { 222 | findSelectedFrames(); 223 | return 1; 224 | } 225 | ).then(() => { 226 | notDayObjects(); 227 | } 228 | ).then(() => figma.closePlugin(`🤘🌗 Dark theme created!`)); 229 | 230 | } 231 | 232 | // SELECTED LIGHT MODE 233 | if (figma.command == 'light') { 234 | async function getPaints() { 235 | var publicColorStyles = await figma.clientStorage.getAsync('allColors'); 236 | var publicEffectStyles = await figma.clientStorage.getAsync('allEffects'); 237 | 238 | if (typeof publicColorStyles === 'undefined') { 239 | await figma.clientStorage.setAsync('allColors', "") 240 | } 241 | if (typeof publicEffectStyles === 'undefined') { 242 | await figma.clientStorage.setAsync('allEffects', "") 243 | } else { 244 | var publicStyles = [...publicColorStyles, ...publicEffectStyles] 245 | // console.log(publicStyles) 246 | } 247 | 248 | var localColorStyles = figma.getLocalPaintStyles(); 249 | var localEffectStyles = figma.getLocalEffectStyles(); 250 | var localStyles = [...localColorStyles, ...localEffectStyles] 251 | // console.log(localStyles) 252 | 253 | var days = {} 254 | var nights = {} 255 | var daysLocal = {} 256 | var nightsLocal = {} 257 | 258 | var dayFromStorage = await figma.clientStorage.getAsync('dayFromStorage') 259 | var nightFromStorage = await figma.clientStorage.getAsync('nightFromStorage') 260 | 261 | if (typeof publicStyles === 'undefined' && localStyles.length == 0) { 262 | figma.closePlugin('😶 This document does not have styles'); 263 | } else { 264 | var importStyles = await Promise.all( 265 | publicStyles.map((styleKey) => 266 | figma.importStyleByKeyAsync(styleKey) 267 | .catch(() => {}) 268 | ) 269 | ); 270 | 271 | if (importStyles[0] == undefined) { 272 | // console.log(importStyles) 273 | var importStyles = []; 274 | } 275 | 276 | var allStyles = [...localStyles, ...importStyles] 277 | // console.log(allStyles) 278 | 279 | //Creating style couples 280 | for (let paintStyle of allStyles) { 281 | const name = paintStyle.name 282 | const id = paintStyle.id 283 | if (name.includes(nightFromStorage)) { 284 | const key = name.replace(nightFromStorage, ''); 285 | nights[key] = id; 286 | nightsLocal[key] = id.slice(0,43); 287 | } else if (name.includes(dayFromStorage)) { 288 | const key = name.replace(dayFromStorage, ''); 289 | days[key] = id; 290 | daysLocal[key] = id.slice(0,43); 291 | } 292 | } 293 | 294 | Object.entries(days).forEach(([name, id]) => { 295 | // object[id] = nights[name]; 296 | object[nights[name]] = id; 297 | }); 298 | 299 | Object.entries(daysLocal).forEach(([name, id]) => { 300 | objectLocal[nightsLocal[name]] = id; 301 | }); 302 | } 303 | } 304 | 305 | // Changing colors 306 | function findSelectedFrames() { 307 | if (figma.currentPage.selection.length == 0) { 308 | figma.closePlugin("🤔 No object selected. Please select any object"); 309 | 310 | } else { 311 | try { 312 | var allSelection = figma.currentPage.selection[0].findAll(); 313 | } catch(error) { 314 | var allSelection = []; 315 | } 316 | allSelection.unshift(figma.currentPage.selection[0]); 317 | } 318 | 319 | for (let frame of allSelection) { 320 | if (frame.fillStyleId && object && object[frame.fillStyleId]) { 321 | frame.fillStyleId = object[frame.fillStyleId]; 322 | counter++ 323 | } 324 | if (frame.effectStyleId && object && object[frame.effectStyleId]) { 325 | frame.effectStyleId = object[frame.effectStyleId]; 326 | counter++; 327 | } 328 | if (frame.strokeStyleId && object && object[frame.strokeStyleId]) { 329 | frame.strokeStyleId = object[frame.strokeStyleId]; 330 | counter++ 331 | } 332 | if (frame.fillStyleId && objectLocal && objectLocal[frame.fillStyleId]) { 333 | frame.fillStyleId = objectLocal[frame.fillStyleId]; 334 | counter++ 335 | } 336 | if (frame.effectStyleId && objectLocal && objectLocal[frame.effectStyleId]) { 337 | frame.effectStyleId = objectLocal[frame.effectStyleId]; 338 | counter++; 339 | } 340 | if (frame.strokeStyleId && objectLocal && objectLocal[frame.strokeStyleId]) { 341 | frame.strokeStyleId = objectLocal[frame.strokeStyleId]; 342 | counter++ 343 | } 344 | } 345 | } 346 | 347 | //Checking night colors 348 | function notNightObjects() { 349 | if (counter == 0) { 350 | figma.closePlugin(`😶 Selection does not have style pairs`); 351 | } 352 | } 353 | 354 | getPaints().then(() => { 355 | findSelectedFrames(); 356 | return 1; 357 | } 358 | ).then(() => { 359 | notNightObjects(); 360 | } 361 | ).then(() => figma.closePlugin(`🤘🌖 Light theme created!`)); 362 | } --------------------------------------------------------------------------------