Add an unread badge to ClickUp in Rambox

Add an unread badge count to ClickUp when using as a custom service in Rambox




File: clickup-rambox-unread-badge.js
-------------------------

 /*
Add this into the Custom Code section in your custom service:
https://github.com/ramboxapp/community-edition/wiki/Add-a-Custom-Service
*/

function checkUnread() {
    // Check for an unread count by looking for the dot favicon
    var unread = document.querySelectorAll("link[href^='favicon-dot-32x32']")

    // Get the document title
    var match = document.title.match(/^(\(1\) )?(.*)/)
    var title = match[3]

    // Put a (1) before the title if necessary, so that Rambox adds the badge
    document.title = unread.length ? `(1) ${title}` : title
}

setInterval(checkUnread, 3000);

Create custom style dropdowns on Quill

I’m putting this one up quickly so the info is out there. If you come across this and need more info, just comment on the post.

Set up the editor:

      // Create editor
      this.editor = new Quill('#' + this.id, {
        modules: {
          toolbar: {
            container: [
              [{'customStyles': this.styleList}],
              [{'align': []}],
              ['bold', 'italic', 'underline', 'strike'],
              [{'list': 'ordered'}, {'list': 'bullet'}],
              [{'color': []}, {'background': []}],
              ['blockquote', 'code-block'],
              [{'indent': '-1'}, {'indent': '+1'}],
              ['clean']
            ],
            handlers: {
              'customStyles': function (index) {
                vm.applyCustomStyle(index)
              }
            }
          }
        },
        theme: 'snow'
      })

      // Add custom style dropdown
      const dropdownPickerItems = Array.prototype.slice.call(document.querySelectorAll('.ql-customStyles .ql-picker-item'))
      dropdownPickerItems.forEach(function (item) {
        item.textContent = vm.customStyles[item.dataset.value]['name']
      })
      document.querySelector('.ql-customStyles .ql-picker-label').innerHTML = 'Styles' + document.querySelector('.ql-customStyles .ql-picker-label').innerHTML

Inject the styles:

      injectStyles () {
        let Block = Quill.import('blots/block')
        let css = ''

        // Register all custom styles
        for (let i = 0; i < this.customStyles.length; i++) {
          let className = this.customStyles[i]['class']
          let element = this.customStyles[i]['element']
          let style = this.customStyles[i]['style']

          // Set up Quill Blot
          class Blot extends Block {
            static create () {
              let node = super.create()
              if (className) {
                node.setAttribute('class', className)
              }
              return node
            }
          }

          Blot.blotName = this.stylePrefix + i
          Blot.tagName = element
          Quill.register(Blot)

          // Create style list for dropdown
          this.styleList.push(i)

          // Create CSS
          let name = (className) ? element + '.' + className : element
          css += '#' + this.id + ' ' + name + '{' + style + '}\n'
        } // Next i

        // Set master CSS
        this.customCSS = css
      },
      applyCustomStyle (index) {
        if (!index) { index = '0' }
        this.editor.format(this.stylePrefix + index, true)
      }

 

Launching renderer functions from the main menu in Electron-Vue

Creating menus is simple enough in Electron, but how in the world do you tell your Renderer process to do something?! I couldn’t find any existing resources on this so hopefully this helps you.

In your menu/index.js  set up your menu:

import { app, BrowserWindow, Menu } from 'electron'

const template = [
  {
    label: 'Test',
    submenu: [
      {
        label: 'Launch a function in Renderer process',
        click: () => { mainWindow.webContents.send('hello', 'Hello World!') }
      }
    ]
  }
]

const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

In your renderer/main.js  add a listening function:

import router from './router'
const electron = require('electron')

electron.ipcRenderer.on('hello', (event, arg) => {
  // Get the current Vue instance (i.e. which component/route is currently active)
  let component = router.currentRoute.matched[0].instances.default

  component.someReactiveData = 'Received message from main process
})

Tada! You can now successfully run any renderer function you like from your application menus. 🙂

Here’s some other types of ways you can communicate between the two processes: http://electron.rocks/different-ways-to-communicate-between-main-and-renderer-process/

How to export from Scrivener to Word with correct styles

This is a macro to export from Scrivener to Word with correct Heading and Body styles. This also correctly handles in-paragraph bold and italics. It is based off the excellent work by Félix Chénier.

When I tried his method, it correctly fixed all the heading styles, but it did not update the body text to be ‘Normal’ style. This is of course a bit of a pain if you want to update style of your whole body text at once.

It would be trivial to add a p.Style = ActiveDocument.Styles(wdStyleNormal)  to his macro assuming that would fix the problem.

However, if you happen to have paragraphs that are comprised solely of italicised or bolded text, then Word will convert those to regular (non italic or bold) text. Apparently if a paragraph is <50% bold or italic, Word assumes those words are for emphasis and keeps them when it does the style conversion. But if it is >50%, then it will turn the whole paragraph just to plain ‘Normal’ style.

So, we have to set as ‘Normal’ and then go through word-by-word and turn the text to its original emphasis.

Fun!!

Luckily I have written the macro for that. It takes your italicised text and temporarily converts it to pink highlighted text. Word does not remove highlights when it converts a paragraph style, so after the conversion the macro knows exactly which words to convert back to the original style. After the conversion it then removes the temporary highlighting. This works for both italic and bold text.

There are two caveats:

  1. If you try and convert your whole document at once, it will simply crash. It’s probably bad coding on my part, maybe someone can suggest a better option. However, if you select 3-4 pages at a time then that seems to work perfectly.
  2. If you happen to have pink or red highlighted text in your document, then you will lose that. Please edit the code to a safe colour!

How to use:

First of all, you need to export from Scrivener with the correct format. Scrivener doesn’t export any special style information, so we will be using a special bit of title suffix text to tell Word which parts of the text are your headings.

The macro can support 6 levels of headingsThe suffixes are in this format:

  1. ~#~ (this corresponds to what you want as Heading 1 in Word)
  2. ~##~ (Heading 2)
  3. ~###~ (Heading 3 …etc…)
  4. ~####~
  5. ~#####~
  6. ~######~

Go to File > Compile, and set up your headings to have a suffix. For Heading 1 it will look like this:

The exported Word document will look something like this:

Title ~#~

Chapter 1 ~##~

It was a dark and stormy night; the rain fell in torrents, except at occasional intervals, when it was checked by a violent gust of wind which swept up the streets (for it is in London that our scene lies), rattling along the house-tops, and fiercely agitating the scanty flame of the lamps that struggled against the darkness.

Chapter 2 – A Story in 3 Parts ~##~

Part 1 ~###~

Through one of the obscurest quarters of London, and among haunts little loved by the gentlemen of the police, a man, evidently of the lowest orders, was wending his solitary way. He stopped twice or thrice at different shops and houses of a description correspondent with the appearance of the quarter in which they were situated, and tended inquiry for some article or another which did not seem easily to be met with.

Part 2 ~###~

All the answers he received were couched in the negative; and as he turned from each door he muttered to himself, in no very elegant phraseology, his disappointment and discontent. At length, at one house, the landlord, a sturdy butcher, after rendering the same reply the inquirer had hitherto received, added, “But if this vill do as vell, Dummie, it is quite at your sarvice!”

You can see how the headings are unstyled, but they have the special suffix added.

Create a macro in your document, and paste this code in:

Sub FormatScrivener()
    FormatWithStyle sTextToFind:="~#~", oStyleToUse:=ActiveDocument.Styles(wdStyleHeading1)
    FormatWithStyle sTextToFind:="~##~", oStyleToUse:=ActiveDocument.Styles(wdStyleHeading2)
    FormatWithStyle sTextToFind:="~###~", oStyleToUse:=ActiveDocument.Styles(wdStyleHeading3)
    FormatWithStyle sTextToFind:="~####~", oStyleToUse:=ActiveDocument.Styles(wdStyleHeading4)
    FormatWithStyle sTextToFind:="~#####~", oStyleToUse:=ActiveDocument.Styles(wdStyleHeading5)
    FormatWithStyle sTextToFind:="~######~", oStyleToUse:=ActiveDocument.Styles(wdStyleHeading6)
    ResetFormatting
End Sub

Sub FormatWithStyle(sTextToFind As String, oStyleToUse As Style)
    Dim oRange As Range
    Set oRange = ActiveDocument.Range
    With oRange
        With .Find
            .ClearFormatting
            .Replacement.ClearFormatting
            .Text = sTextToFind
            .Format = True
            .Replacement.Style = oStyleToUse
            .Replacement.Text = " "
            .Forward = True
            .Wrap = wdFindContinue
            .Execute Replace:=wdReplaceAll
        End With
    End With
End Sub

Sub ResetFormatting()
    Dim p As Paragraph

    For Each p In ActiveDocument.Paragraphs
        If p.Range.Style = ActiveDocument.Styles(wdStyleHeading1) Then
            p.Range.Style = ActiveDocument.Styles(wdStyleHeading1)
        ElseIf p.Range.Style = ActiveDocument.Styles(wdStyleHeading2) Then
            p.Range.Style = ActiveDocument.Styles(wdStyleHeading2)
        ElseIf p.Range.Style = ActiveDocument.Styles(wdStyleHeading3) Then
            p.Range.Style = ActiveDocument.Styles(wdStyleHeading3)
        ElseIf p.Range.Style = ActiveDocument.Styles(wdStyleHeading4) Then
            p.Range.Style = ActiveDocument.Styles(wdStyleHeading4)
        ElseIf p.Range.Style = ActiveDocument.Styles(wdStyleHeading5) Then
            p.Range.Style = ActiveDocument.Styles(wdStyleHeading5)
        ElseIf p.Range.Style = ActiveDocument.Styles(wdStyleTitle) Then
            p.Range.Style = ActiveDocument.Styles(wdStyleTitle)
        Else
              Dim oWord As Range
            ' Here we do the "Normal" style
            For Each oWord In p.Range.Words
                If oWord.Font.Italic = True Then
                    oWord.HighlightColorIndex = wdPink
                ElseIf oWord.Font.Bold = True Then
                    oWord.HighlightColorIndex = wdRed
                End If
            Next oWord
            p.Style = ActiveDocument.Styles(wdStyleNormal)
            For Each oWord In p.Range.Words
                If oWord.HighlightColorIndex = wdPink Then
                    oWord.Font.Italic = True
                    oWord.HighlightColorIndex = wdAuto
                ElseIf oWord.HighlightColorIndex = wdRed Then
                    oWord.Font.Bold = True
                    oWord.HighlightColorIndex = wdAuto
                End If
            Next oWord
        End If
    Next
End Sub

Set the macro to either a keyboard shortcut, or put a custom button on your toolbar.

Go through your book maybe 3-4 pages at a time. Select the text, then run the macro. Only do a few pages at a time, otherwise the macro will fail.

It shouldn’t take you too long to do the whole book at that speed, and then you’re done!