Skip to content

Instantly share code, notes, and snippets.

@Klustre
Last active April 4, 2023 16:08
Show Gist options
  • Save Klustre/956fcdafd5285f44793b62fb8755f6c3 to your computer and use it in GitHub Desktop.
Save Klustre/956fcdafd5285f44793b62fb8755f6c3 to your computer and use it in GitHub Desktop.
Generate a KBar toolbar

node-kbar

Generate a KBar toolbar with NodeJS

Note: This only creates script buttons with SVG icons and a single script file

Why?

Manually creating a toolbar for every product update is tedious. Save time and avoid release anxiety by automating it.

Usage

  1. Simply define the constants at the top by following the TODO items
  2. Make sure you install the dependencies with npm i fs-extra adm-zip -D
  3. Set "type": "module" in your package.json
  4. Run with node ./node-kbar.js

Works well with extender

/**
* Generate a KBar toolbar
* But only script buttons with svg icons and a single script file
*/
import { randomUUID } from 'crypto'
import { join } from 'path'
// TODO: Install dependencies `npm i fs-extra adm-zip -D`
import fs from 'fs-extra'
import AdmZip from 'adm-zip'
const { name, displayName } = await fs.readJson('./package.json')
// TODO: Use `package.json` or hardcode the values
// const name = ''
// const displayName = ''
const toolbarName = `${name}.kbar`
const scriptFile = `${name}.jsx`
const scriptPath = `./dist/${scriptFile}`
const outputFile = `./dist/${toolbarName}`
// NOTE: SVG icons should be named after the argument, ie. `Rectangle.svg`
const iconsPath = `./static/icons/`
// TODO: Define your various button arguments
const args = ['Rectangle', 'Ellipse', 'Polygon', 'Path']
const buttons = args.map((argument) => ({
// TODO: Define the button's name
name: `Create ${argument}`,
// TODO: And an optional description
description: '',
argument,
}))
// NOTE: Magic, don't touch without a wand
const config = {
version: 1,
isBaked: true,
notes: displayName,
createdDate: new Date().toISOString(),
scripts: [{ source: scriptFile }],
presets: [],
shell: [],
toolbar: {
id: randomUUID(),
name: displayName,
buttons: buttons.map((button) => ({
...button,
icon: {
type: 2,
color: '',
path: readSVGAsDataURL(
join(iconsPath, `${button.argument}.svg`)
),
},
type: 1,
filePath: 'kzip://scripts/0',
id: randomUUID(),
modifiers: {
ctrl: null,
alt: null,
shift: null,
altshift: null,
ctrlalt: null,
ctrlshift: null,
ctrlaltshift: null
},
})),
},
}
function readSVGAsDataURL(path) {
const file = fs.readFileSync(path, 'utf-8')
return `data:image/svg+xml;utf8,${file}`
}
async function exportToolbar() {
try {
const zip = new AdmZip()
const json = JSON.stringify(config)
const manifest = Buffer.from(json)
const subFolder = '/scripts'
zip.addFile('manifest.json', manifest)
zip.addLocalFile(scriptPath, subFolder)
zip.writeZip(outputFile)
console.log(`Successfully created ${toolbarName}`)
} catch (error) {
console.error(error)
}
}
exportToolbar()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment