Turn your pages into interactive applications! JavaScript Mini-Apps (Input & Output, no persistent state)

I have been playing around with making JavaScript ‘mini-apps’ in Logseq.

There is no persistent storage, so think of these are more like utilities that could help you in your day to day life.

The cool thing about this is that they can run within the standard Logseq app.

Here is a basic example, you could use this to make anything. Not sure if it works on mobile.

To use the ‘mini-apps’, just run the macro, for example the macro below generates the ‘mini-app’ in the screenshot below.

- {{convert-epoch-to-datetime-string-html-io}}

These are little JavaScript + HTML “pages” that can contain entire user interfaces, with user inputs and buttons!

I made a basic example below, it takes an input in the form of the Unix epoch time in seconds or milliseconds and converts that date into something human readable.

You can use the buttons to generate a random date, or the now date if you prefer.

The output field is actually an input field that will automatically select the output/result text when you enter you cursor, this lets you quickly use these ‘mini-apps’ / ‘utilities’ to generate output/content and then quickly copy that text for other uses.

To Install:

Add this as your first ‘mini-app’ in your config.edn

:macros
{:convert-epoch-to-datetime-string-html-io
 "<style onload='Function(this.innerHTML.slice(2, this.innerHTML.length - 2))()'>/*

 function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  function convertEpochDateToDateString(epochDate) {
    if (String(epochDate).length <= 10) {
      epochDate = epochDate * 1000;
    }
    var d = new Date(parseInt(epochDate));
    return d.toString();
  }

  const source = document.getElementById('convert-epoch-to-datetime-string-text-input');
  const result = document.getElementById('convert-epoch-to-datetime-string-output');

  const inputHandler = function(e) {
    var dateString = convertEpochDateToDateString(e.target.value);
    result.innerHTML = dateString;
  }

  document.getElementById('convert-epoch-to-datetime-string-example-button').onclick = function(e) {
    e.preventDefault();
    var min = 0;
    var max = new Date().getTime();
    var randNum = getRandomInt(min, max);
    source.value = randNum;

    var dateString = convertEpochDateToDateString(randNum);
    result.value = dateString;
  }

  document.getElementById('convert-epoch-to-datetime-string-now-date-button').onclick = function(e) {
    e.preventDefault();
    var nowDate = new Date().getTime();
    source.value = nowDate;
    var dateString = convertEpochDateToDateString(nowDate);
    result.value = dateString;
  }

  source.addEventListener('input', inputHandler);

  */</style>
<div class='js-mini-app-container'>
  <div class='js-mini-app-input-container'>
    <div class='js-mini-app-label-container js-mini-app-input-label-container'>
      <label for='convert-epoch-to-datetime-string-text-input' class='js-mini-app-label js-mini-app-input-label'>Input:</label>
    </div>
    <input id='convert-epoch-to-datetime-string-text-input' class='js-mini-app-input convert-epoch-to-datetime-string-input'>
    <button id='convert-epoch-to-datetime-string-example-button' class='js-mini-app-button'>Example (Random Date)</button>
    <button id='convert-epoch-to-datetime-string-now-date-button' class='js-mini-app-button'>Now Date</button>
  </div>
  <div class='js-mini-app-output-container'>
    <div class='js-mini-app-label-container js-mini-app-output-label-container'>
      <label for='convert-epoch-to-datetime-string-output' class='js-mini-app-label js-mini-app-output-label'>Output:</label>
    </div>
    <input onfocus=\"this.select();\" onmouseup=\"return false;\" id='convert-epoch-to-datetime-string-output' class='js-mini-app-output convert-epoch-to-datetime-string-output'>
  </div>
</div>"}

Add these CSS styles to your custom.css

/*********************************
****
**** mini js apps (config macros)
****
****/

/**** Generic ****/

.js-mini-app-container {
  display: grid;
}
.js-mini-app-container div {
  display: grid;
}
.js-mini-app-input-container {

}
.js-mini-app-output-container {
  margin-top: 10px;
}
.js-mini-app-label-container {
  margin-bottom: 3px;
}

.js-mini-app-input {
  width: 200px;
  color: rgb(20 30 50 / 90%);
  background-color: rgb(245 245 245 / 70%);
  padding: 3px;
  border: 1px solid rgb(30 150 240 / 80%);
  border-radius: 4px;
  margin-bottom: 3px;
}
.js-mini-app-output {
  width: 200px;
  height: 38px;
  color: rgb(30 150 255 / 100%);
  background-color: rgb(245 245 245 / 15%);
  padding: 6px;
  border: 1px solid rgb(30 150 240 / 60%);
  border-radius: 4px;
}
.js-mini-app-button {
  width: 120px;
  height: 35px;
  margin-top: 4px;
  color: rgb(30 150 240 / 80%);
  background-color: rgb(30 150 240 / 10%);
  border: 1px solid rgb(30 150 240 / 80%);
  border-radius: 4px;
}
.js-mini-app-button:hover {
  color: rgb(30 150 240 / 60%);
  background-color: rgb(30 150 240 / 4%);
  border: 1px solid rgb(30 150 240 / 60%);
}

/**** convert-epoch-to-datetime-string-html-io ****/

.convert-epoch-to-datetime-string-input {

}
.convert-epoch-to-datetime-string-output {
  height: 38px;
  min-width: 200px;
  width: 100%;
}
#convert-epoch-to-datetime-string-example-button,
#convert-epoch-to-datetime-string-now-date-button {
  width: 200px;
}

Now you should be able to use the macro {{convert-epoch-to-datetime-string-html-io}} in your pages.

That is it!

All that was needed was the macro defined in config.edn and some CSS styles, and you can fill up your Logseq graph with whatever marvelous utilities you can imagine.

Let me know how you go.

I like this as a quick way to make little handy utilities.


Further reading and Notes

The magic that lets you run JavaScript this way are these lines (see the macro above and see how the JavaScript is contained within them):

 <style onload='Function(this.innerHTML.slice(2, this.innerHTML.length - 2))()'>/*
 /* JavaScript goes here... */
 */</style>

I got this trick from this link: https://github.com/71/logseq-snippets

That links goes into more complicated stuff, for example, combining this with persistent storage!