{"id":24456029,"url":"https://github.com/jasonm23/phoenix-config","last_synced_at":"2025-08-07T04:32:53.119Z","repository":{"id":19102914,"uuid":"22331302","full_name":"jasonm23/Phoenix-config","owner":"jasonm23","description":"Literate JS configuration for the scriptable OSX Automation tool 'Phoenix'","archived":false,"fork":false,"pushed_at":"2023-07-26T02:14:45.000Z","size":2611,"stargazers_count":17,"open_issues_count":0,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-08T04:15:24.614Z","etag":null,"topics":["automation","gui","macos","phoenix-application"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jasonm23.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-07-28T04:54:05.000Z","updated_at":"2024-10-04T00:48:41.000Z","dependencies_parsed_at":"2025-04-13T02:39:12.776Z","dependency_job_id":null,"html_url":"https://github.com/jasonm23/Phoenix-config","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/jasonm23/Phoenix-config","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonm23%2FPhoenix-config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonm23%2FPhoenix-config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonm23%2FPhoenix-config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonm23%2FPhoenix-config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jasonm23","download_url":"https://codeload.github.com/jasonm23/Phoenix-config/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonm23%2FPhoenix-config/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269200381,"owners_count":24377431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-07T02:00:09.698Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","gui","macos","phoenix-application"],"created_at":"2025-01-21T02:15:04.205Z","updated_at":"2025-08-07T04:32:53.046Z","avatar_url":"https://github.com/jasonm23.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Phoenix config\n### Tested with Phoenix 4.0.0\n\nThis is a literate (JS) config for [Phoenix](https://github.com/kasper/phoenix/)\na lightweight scriptable OS X window manager.\n\nPrimary feature here is grid based window control and layout. Move and size\nwindows around the grid. Resize grid. Snap window or windows to grid.\n\n## Clone and Install\n\n```bash\ncd\ngit clone git@github.com:jasonm23/Phoenix-config\ncd Phoenix-config\nmake\n```\n\n# Code\n\n## Helpers\n\n```js @code\nPhoenix.notify(\"Phoenix config loading\")\n\nPhoenix.set({\n  daemon: false,\n  openAtLogin: true\n})\n```\n\nLogging\n\n```js @code\nlet log = function (o, label = \"obj: \") {\n  Phoenix.log(`${(new Date()).toISOString()}:: ${label} =\u003e`)\n  Phoenix.log(JSON.stringify(o))\n}\n```\n\nAdd `_.flatmap` to `lodash`.\n\n```js @code\n_.mixin({\n  flatmap(list, iteratee, context) {\n    return _.flatten(_.map(list, iteratee, context))\n  }\n})\n```\n\n- - -\n\n## Window Grid\n\nInitial grid settings\n\n```js @code\nMARGIN_X = 0\nMARGIN_Y = 0\nGRID_WIDTH = 16 \nGRID_HEIGHT = 9\n```\n\nShortcuts for `focused` and `visible`\n\n```js @code\nfocused = () =\u003e Window.focused()\n\nfunction visible() { \n  return Window.all().filter( w =\u003e {\n    if (w != undefined) { \n      return w.isVisible()\n    } else {\n      return false\n    }\n  })\n}\n\nWindow.prototype.screenFrame = function(screen) {\n  return (screen != null ? screen.flippedVisibleFrame() : void 0) || this.screen().flippedVisibleFrame()\n}\n\nWindow.prototype.fullGridFrame = function() {\n  return this.calculateGrid({y: 0, x: 0, width: 1, height: 1})\n}\n```\n\nSnap all windows to grid layout\n\n```js @code\nfunction snapAllToGrid() { _.map(visible(), win =\u003e win.snapToGrid()) }\n```\n\nChange grid width or height\n\n```js @code\nchangeGridWidth = n =\u003e {\n  GRID_WIDTH = Math.max(1, GRID_WIDTH + n)\n  Phoenix.notify(`grid is ${GRID_WIDTH} tiles wide`)\n  snapAllToGrid()\n  return GRID_WIDTH\n}\n\nchangeGridHeight = n =\u003e {\n  GRID_HEIGHT = Math.max(1, GRID_HEIGHT + n)\n  Phoenix.notify(`grid is ${GRID_HEIGHT} tiles high`)\n  snapAllToGrid()\n  return GRID_HEIGHT\n}\n```\n\nGet the grid box size\n\n```js @code\nWindow.prototype.getBoxSize = function() {\n  return [this.screenFrame().width / GRID_WIDTH, \n          this.screenFrame().height / GRID_HEIGHT]\n}\n```\n\nGet the current window `grid` as `rect`:\n\n```js\n// rectangle \n{x: float, y: float, width: float, height: float}\n```\n\n```js @code\nWindow.prototype.getGrid = function() {\n  let frame = this.frame()\n  let [boxHeight, boxWidth] = this.getBoxSize() \n  let grid = {\n    y: Math.round((frame.y - this.screenFrame().y) / boxHeight),\n    x: Math.round((frame.x - this.screenFrame().x) / boxWidth),\n    width: Math.max(1, Math.round(frame.width / boxWidth)),\n    height: Math.max(1, Math.round(frame.height / boxHeight))\n  }\n  log(`Window grid: ${grid}`)\n  return grid\n}\n```\n\nSet the current grid from  `rectangle`\n\n```js @code\nWindow.prototype.setGrid = function({y, x, width, height}, screen) {\n  let gridHeight, gridWidth\n  screen = screen || focused().screen()\n  gridWidth = this.screenFrame().width / GRID_WIDTH\n  gridHeight = this.screenFrame().height / GRID_HEIGHT\n  return this.setFrame({\n    y: ((y * gridHeight) + this.screenFrame(screen).y) + MARGIN_Y,\n    x: ((x * gridWidth) + this.screenFrame(screen).x) + MARGIN_X,\n    width: (width * gridWidth) - (MARGIN_X * 2.0),\n    height: (height * gridHeight) - (MARGIN_Y * 2.0)\n  })\n}\n```\n\nSnap the current window to the grid\n\n```js @code\nWindow.prototype.snapToGrid = function() {\n  if (this.isNormal()) {\n    return this.setGrid(this.getGrid())\n  }\n}\n```\n\nCalculate the grid based on the parameters, `x`, `y`, `width`, `height`, (returning an object `rectangle`)\n\n```js @code\nWindow.prototype.calculateGrid = function({x, y, width, height}) {\n  return {\n    y: Math.round(y * this.screenFrame().height) + MARGIN_Y + this.screenFrame().y,\n    x: Math.round(x * this.screenFrame().width) + MARGIN_X + this.screenFrame().x,\n    width: Math.round(width * this.screenFrame().width) - 2.0 * MARGIN_X,\n    height: Math.round(height * this.screenFrame().height) - 2.0 * MARGIN_Y\n  }\n}\n```\n\nWindow proportion width\n\n```js @code\nWindow.prototype.proportionWidth = function() {\n  let s_w, w_w\n  s_w = this.screenFrame().width\n  w_w = this.frame().width\n  return Math.round((w_w / s_w) * 10) / 10\n}\n```\n\nWindow to grid\n\n```js @code\nWindow.prototype.toGrid = function({x, y, width, height}) {\n  let rect = this.calculateGrid({x, y, width, height})\n  return this.setFrame(rect)\n}\n```\n\nWindow top right point\n\n```js @code\nWindow.prototype.topRight = function() {\n  return {\n    x: this.frame().x + this.frame().width,\n    y: this.frame().y\n  }\n}\n```\n\nWindows on the left of the current window.\n\n```js @code\nWindow.prototype.toLeft = function() {\n  return _.filter(this.neighbors('west'), function(win) {\n    return win.topLeft().x \u003c this.topLeft().x - 10\n  })\n}\n```\n\nWindows on the right of the current window.\n\n```js @code\nWindow.prototype.toRight = function() {\n  return _.filter(this.neighbors('east'), function(win) {\n    return win.topRight().x \u003e this.topRight().x + 10\n  })\n}\n\n```\n\nWindow information\n\n```js @code\nWindow.prototype.info = function() {\n  let f = this.frame()\n  return `[${this.app().processIdentifier()}] ${this.app().name()} : ${this.title()}\\n{x:${f.x}, y:${f.y}, width:${f.width}, height:${f.height}}\\n`\n}\n```\n\n## Window moving and sizing\n\nTemporary storage for frames\n\n```js @code\nlastFrames = {}\n```\n\nToggle a window to full screen or revert to it's former frame size.\n\n```js @code\nWindow.prototype.toFullScreen = function(toggle = true) {\n  if (!_.isEqual(this.frame(), this.fullGridFrame())) {\n    this.rememberFrame()\n    return this.toGrid({y: 0, x: 0, width: 1, height: 1})\n  } else if (toggle \u0026\u0026 lastFrames[this.uid()]) {\n    this.setFrame(lastFrames[this.uid()])\n    return this.forgetFrame()\n  }\n}\n```\n\nRemember and forget frames\n\n```js @code\nWindow.prototype.uid = function() {\n  return `${this.app().name()}::${this.title()}`\n}\n\nWindow.prototype.rememberFrame = function() {\n  return lastFrames[this.uid()] = this.frame()\n}\n\nWindow.prototype.forgetFrame = function() {\n  return delete lastFrames[this.uid()]\n}\n```\n\n\u003ca name=\"toggling-width\"/\u003e\nToggle window width 80%, 50%, 30%\n\n```js @code\nWindow.prototype.togglingWidth = function() {\n  switch (this.proportionWidth()) {\n    case 0.8:\n      return 0.5\n    case 0.5:\n      return 0.3\n    default:\n      return 0.8\n  }\n}\n```\n\n#### Screen halves\n\n``` text\n┌───────────────────────┐\n│                       │\n│                       │\n│                       │\n├───────────────────────┤\n│                       │\n│                       │\n│                       │\n└───────────────────────┘\n┌───────────┬───────────┐\n│           │           │\n│           │           │\n│           │           │\n│           │           │\n│           │           │\n│           │           │\n│           │           │\n└───────────┴───────────┘\n```\n\n\n```js @code\nWindow.prototype.toTopHalf = function() {\n  return this.toGrid({x: 0, y: 0, width: 1, height: 0.5})\n}\n\nWindow.prototype.toBottomHalf = function() {\n  return this.toGrid({x: 0, y: 0.5, width: 1, height: 0.5})\n}\n\nWindow.prototype.toLeftHalf = function() {\n  return this.toGrid({x: 0, y: 0, width: 0.5, height: 1})\n}\n\nWindow.prototype.toRightHalf = function() {\n  return this.toGrid({x: 0.5, y: 0, width: 0.5, height: 1})\n}\n\n```\n\n#### Left/Right Sides with [toggling width](#toggling-width).\n\n``` text\n┌──────┬────────────────┐\n│      │                │\n│      │                │\n│      │                │\n│      │                │\n│      │                │\n│      │                │\n│      │                │\n└──────┴────────────────┘\n┌───────────┬───────────┐\n│           │           │\n│           │           │\n│           │           │\n│           │           │\n│           │           │\n│           │           │\n│           │           │\n└───────────┴───────────┘\n┌────────────────┬──────┐\n│                │      │\n│                │      │\n│                │      │\n│                │      │\n│                │      │\n│                │      │\n│                │      │\n└────────────────┴──────┘\n```\n\n```js @code\nWindow.prototype.toLeftToggle = function() {\n  return this.toGrid({\n    x: 0,\n    y: 0,\n    width: this.togglingWidth(),\n    height: 1\n  })\n}\n\nWindow.prototype.toRightToggle = function() {\n  return this.toGrid({\n    x: 1 - this.togglingWidth(),\n    y: 0,\n    width: this.togglingWidth(),\n    height: 1\n  })\n}\n```\n\n#### To screen corners\n\n``` text\n┌───────────┬───────────┐\n│           │           │\n│           │           │\n│           │           │\n├───────────┘           │\n│                       │\n│                       │\n│                       │\n└───────────────────────┘\n┌───────────┬───────────┐\n│           │           │\n│           │           │\n│           │           │\n│           └───────────┤\n│                       │\n│                       │\n│                       │\n└───────────────────────┘\n┌───────────────────────┐\n│                       │\n│                       │\n│                       │\n├───────────┐           │\n│           │           │\n│           │           │\n│           │           │\n└───────────┴───────────┘\n┌───────────────────────┐\n│                       │\n│                       │\n│                       │\n│           ┌───────────┤\n│           │           │\n│           │           │\n│           │           │\n└───────────┴───────────┘\n```\n\n\n```js @code\nWindow.prototype.toTopRight = function() {\n  return this.toGrid({x: 0.5, y: 0, width: 0.5, height: 0.5})\n}\n\nWindow.prototype.toBottomRight = function() {\n  return this.toGrid({x: 0.5, y: 0.5, width: 0.5, height: 0.5})\n}\n\nWindow.prototype.toTopLeft = function() {\n  return this.toGrid({x: 0, y: 0, width: 0.5, height: 0.5})\n}\n\nWindow.prototype.toBottomLeft = function() {\n  return this.toGrid({x: 0, y: 0.5, width: 0.5, height: 0.5})\n}\n```\n\nTo the center of the screen with a grid border.\n\n``` text\n┌───────────────────────┐\n│                       │\n│   ┌───────────────┐   │\n│   │               │   │\n│   │               │   │\n│   │               │   │\n│   │               │   │\n│   └───────────────┘   │\n│                       │\n└───────────────────────┘\n```\n\n```js @code\nWindow.prototype.toCenterWithBorder = function(border = 1) {\n  let [boxWidth, boxHeight] = this.getBoxSize()\n  let rect = { \n               x: border,\n               y: border, \n               width: GRID_WIDTH - (border * 2), \n               height: GRID_HEIGHT - (border * 2) \n             }\n  this.setGrid(rect)\n}\n```\n\n### Move the current window around the grid\n\n```js @code\nwindowLeftOneColumn = () =\u003e {\n  let frame = focused().getGrid()\n  frame.x = Math.max(frame.x - 1, 0)\n  return focused().setGrid(frame)\n}\n\nwindowDownOneRow = () =\u003e {\n  let frame = focused().getGrid()\n  frame.y = Math.min(Math.floor(frame.y + 1), GRID_HEIGHT - 1)\n  return focused().setGrid(frame)\n}\n\nwindowUpOneRow = () =\u003e {\n  let frame = focused().getGrid()\n  frame.y = Math.max(Math.floor(frame.y - 1), 0)\n  return focused().setGrid(frame)\n}\n\nwindowRightOneColumn = () =\u003e {\n  let frame = focused().getGrid()\n  frame.x = Math.min(frame.x + 1, GRID_WIDTH - frame.width)\n  return focused().setGrid(frame)\n}\n```\n\nResize the current window on the grid\n\n```js @code\nwindowGrowOneGridColumn = () =\u003e {\n  let frame = focused().getGrid()\n  frame.width = Math.min(frame.width + 1, GRID_WIDTH - frame.x)\n  return focused().setGrid(frame)\n}\n\nwindowShrinkOneGridColumn = () =\u003e {\n  let frame = focused().getGrid()\n  frame.width = Math.max(frame.width - 1, 1)\n  return focused().setGrid(frame)\n}\n\nwindowGrowOneGridRow = () =\u003e {\n  let frame = focused().getGrid()\n  frame.height = Math.min(frame.height + 1, GRID_HEIGHT)\n  return focused().setGrid(frame)\n}\n\nwindowShrinkOneGridRow = () =\u003e {\n  let frame = focused().getGrid()\n  frame.height = Math.max(frame.height - 1, 1)\n  return focused().setGrid(frame)\n}\n```\n\nExpand the current window's height to vertically fill the screen\n\n```js @code\nwindowToFullHeight = () =\u003e {\n  let frame = focused().getGrid()\n  frame.y = 0\n  frame.height = GRID_HEIGHT\n  return focused().setGrid(frame)\n}\n```\n\nExpand the current window's width to horizontally fill the screen\n\n```js @code\nwindowToFullWidth = () =\u003e {\n  let frame = focused().getGrid()\n  frame.x = 0\n  frame.width = GRID_WIDTH\n  return focused().setGrid(frame)\n}\n```\n\n## Multi-screen  helpers...\n\nMove the current window to the next / previous screen\n\n```js @code\nmoveWindowToNextScreen = () =\u003e focused().setGrid(focused().getGrid(), focused().screen().next())\nmoveWindowToPreviousScreen = () =\u003e focused().setGrid(focused().getGrid(), focused().screen().previous())\n```\n\n## Applications\n\nSelect the first window for an app\n\n```js @code\nApp.prototype.firstWindow = function() {\n  return this.all({\n    visible: true\n  })[0]\n}\n```\n\nFind an app by it's `name` - this is problematic when the App window\nhas no title bar. Fair warning.\n\nFind all apps with `name`\n\n```js @code\nApp.allWithName = name =\u003e _.filter(App.all(), a =\u003e a.name() === name)\n\nApp.byName = name =\u003e {\n  let app = _.first(App.allWithName(name))\n  app.show()\n  return app\n}\n```\n\nFocus or start an app with `name`\n\n```js @code\nApp.focusOrStart = name =\u003e {\n  let apps = App.allWithName(name)\n  \n  if (_.isEmpty(apps)) {\n    App.launch(name)\n  }\n  \n  let windows = _.flatmap(apps, x =\u003e x.windows())\n  let activeWindows = _.reject(windows, win =\u003e win.isMinimized())\n  \n  if (_.isEmpty(activeWindows)) {\n    App.launch(name)\n  }\n  \n  return _.each(activeWindows, win =\u003e win.focus())\n}\n```\n\n# Applications\n\nLaunch apps\n\n```js @code\nITERM = \"iTerm2\"\nEMACS = \"Emacs\"\nFINDER = \"Finder\"\nFIREFOX = \"Firefox\"\n```\n\n### App Name Modal\n\nShow App name.  To be honest, I just added this to see the modal feature in Phoenix.\n\n```js @code\nlet showAppName = () =\u003e {\n  let name = focused().app().name()\n  let frame = focused().screenFrame()\n  let modal = Modal.build({\n    duration: 2,\n    text: `App: ${name}`\n  })\n  modal.origin = {\n    x: (frame.width / 2) - modal.frame().width / 2,\n    y: frame.height - 100\n  }\n  modal.show()\n}\n```\n\n(It's  pretty cool, but it's clearly a bezel ;)\n\n### Binding alias\n\nAlias `Phoenix.bind` as `bind_key`, to make the binding table extra\nreadable.\n\n```js @code\nkeys = []\n```\n\nThe `bind_key` method includes the unused `description` parameter,\nThis is to allow future functionality i.e. help mechanisms, describe bindings etc.\n\n```js @code\nconst bind_key = (key, description, modifier, fn) =\u003e keys.push(Key.on(key, modifier, fn))\n```\n\n## Bindings\n\nMash is \u003ckbd\u003eCmd\u003c/kbd\u003e + \u003ckbd\u003eAlt/Opt\u003c/kbd\u003e + \u003ckbd\u003eCtrl\u003c/kbd\u003e pressed together.\n\n```js @code\nconst mash = 'cmd-alt-ctrl'.split('-')\n```\n\nSmash is Mash + \u003ckbd\u003eshift\u003c/kbd\u003e\n\n```js @code\nconst smash = 'cmd-alt-ctrl-shift'.split('-')\n```\n\nMove the current window to the top / bottom / left / right half of the screen\nand fill it.\n\n```js @code\nbind_key('up', 'Top Half', mash, () =\u003e focused().toTopHalf())\nbind_key('down', 'Bottom Half', mash, () =\u003e focused().toBottomHalf())\nbind_key('left', 'Left side toggle', mash, () =\u003e focused().toLeftToggle())\nbind_key('right', 'Right side toggle', mash, () =\u003e focused().toRightToggle())\n```\n\nMove to the center of the screen as a square\n\n```js @code\nbind_key('C', 'Center with border', mash, () =\u003e focused().toCenterWithBorder(1))\n```\n\nMove to the corners of the screen\n\n```js @code\nbind_key('Q', 'Top Left', mash, () =\u003e focused().toTopLeft())\nbind_key('A', 'Bottom Left', mash, () =\u003e focused().toBottomLeft())\nbind_key('W', 'Top Right', mash, () =\u003e focused().toTopRight())\nbind_key('S', 'Bottom Right', mash, () =\u003e focused().toBottomRight())\n```\n\nMove to left / right half of the screen.\n\n```js @code\nbind_key('z', 'Right Half', mash, () =\u003e focused().toLeftHalf())\nbind_key('x', 'Left Half', mash, () =\u003e focused().toRightHalf())\n```\n\nToggle maximize for the current window\n\n```js @code\nbind_key('space', 'Maximize Window', mash, () =\u003e focused().toFullScreen())\nbind_key('return', 'Maximize Window', mash, () =\u003e focused().toFullScreen())\n```\n\nSwitch to or launch apps - fix these up to use whatever Apps you want on speed dial.\n\n```js @code\nbind_key('1', 'Show App Name', mash, showAppName) \nbind_key('E', 'Launch Emacs', mash, () =\u003e App.focusOrStart(EMACS))\nbind_key('T', 'Launch iTerm2', mash, () =\u003e App.focusOrStart(ITERM))\nbind_key('B', 'Launch Browser', mash, () =\u003e App.focusOrStart(FIREFOX))\nbind_key('F', 'Launch Finder', mash, () =\u003e App.focusOrStart(FINDER))\n```\n\nMove window between screens\n\n```js @code\nbind_key('N', 'To Next Screen', mash, moveWindowToNextScreen)\nbind_key('P', 'To Previous Screen', mash, moveWindowToPreviousScreen)\n```\n\nSetting the grid size\n\n```js @code\nbind_key('=', 'Increase Grid Columns', mash, () =\u003e changeGridWidth(+1))\nbind_key('-', 'Reduce Grid Columns', mash, () =\u003e changeGridWidth(-1))\nbind_key(']', 'Increase Grid Rows', mash, () =\u003e changeGridHeight(+1))\nbind_key('[', 'Reduce Grid Rows', mash, () =\u003e changeGridHeight(-1))\n```\n\nSnap current window or all windows to the grid\n\n```js @code\nbind_key(';', 'Snap focused to grid', mash, () =\u003e focused().snapToGrid())\nbind_key(\"'\", 'Snap all to grid', mash, function(){ visible().map(win =\u003e win.snapToGrid()) })\n```\n\nMove the current window around the grid\n\n```js @code\nbind_key('H', 'Move Grid Left', mash, windowLeftOneColumn)\nbind_key('J', 'Move Grid Down', mash, windowDownOneRow)\nbind_key('K', 'Move Grid Up', mash, windowUpOneRow)\nbind_key('L', 'Move Grid Right', mash, windowRightOneColumn)\nbind_key('6', 'Move Grid Left', mash, windowLeftOneColumn)\nbind_key('7', 'Move Grid Down', mash, windowDownOneRow)\nbind_key('8', 'Move Grid Up', mash, windowUpOneRow)\nbind_key('9', 'Move Grid Right', mash, windowRightOneColumn)\n```\n\nSize the current window on the grid\n\n```js @code\nbind_key('U', 'Window Full Height', mash, windowToFullHeight)\nbind_key('Y', 'Window Full Height', mash, windowToFullWidth)\nbind_key('I', 'Shrink by One Column', mash, windowShrinkOneGridColumn)\nbind_key('O', 'Grow by One Column', mash, windowGrowOneGridColumn)\nbind_key(',', 'Shrink by One Row', mash, windowShrinkOneGridRow)\nbind_key('.', 'Grow by One Row', mash, windowGrowOneGridRow)\n```\n\n### Markdown editing layout.\n\nPlace Firefox and Emacs windows side-by-side.\n\n```js @code\nbind_key('M', 'Markdown Editing', mash, () =\u003e {\n  App.focusOrStart(FIREFOX) \n  focused().toRightHalf()\n  App.focusOrStart(EMACS)\n  focused().toLeftHalf()\n})\n\nbind_key('M', 'Exit Markdown Editing', smash, () =\u003e {\n  App.focusOrStart(FIREFOX)\n  focused().toFullScreen(false)\n  App.focusOrStart(EMACS)\n  focused().toFullScreen(false)\n})\n```\n\nAll done...\n\n```js @code\nPhoenix.notify(\"All ok.\")\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasonm23%2Fphoenix-config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjasonm23%2Fphoenix-config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasonm23%2Fphoenix-config/lists"}