krasnovpro / hammerspoon.org Documentation

// ==UserScript==
// @name         hammerspoon.org Documentation
// @license      MIT
// @version      2019.08.16
// @description  Add TOC
// @author       krasnovpro
// @include      /^https?://(.*hammerspoon\.org/(docs|Spoons)|(127\.0\.0\.1|localhost):12345)/.*$/
// @updateURL    https://openuserjs.org/meta/krasnovpro/hammerspoon.org_Documentation.meta.js
// @downloadURL  https://openuserjs.org/src/scripts/krasnovpro/hammerspoon.org_Documentation.user.js

// @require      https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
// @grant        none
// ==/UserScript==

let cssToc = `<style>
html {
  left: 0;
  top: 30px;
}

body {
  background: var(--line);
  padding: 0;
  margin-top: 0;
}

td, p, li {
  font-family: var(--ftitle);
  font-size: var(--fsize);
  font-weight: 100;
}

.api-documentation-overview th,
.api-documentation-overview td {
  border-top: 1px solid #444;
  padding-top: calc(var(--margin) / 3);
  padding-left: var(--margin);
}
</style>`.trim();

let cssIndex = `<style>
header>h1 {
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
}

/* top urls block */
.urls {
  height: 1.3em;
  overflow: hidden;
  margin-bottom: var(--margin);
  padding: var(--margin);
  padding-top: 0;
  transition: height .3s ease-in-out;
}

.urls:hover {
  height: 13em;
}

.urls * {
  font-size: var(--fsize);
  line-height: var(--flheight);
}

.urls tr:first-of-type,
.urls+br,
body>br {
  display: none !important;
}

.api-documentation-overview th,
.api-documentation-overview td {
  border-top: 1px solid var(--line);
  padding-top: calc(var(--margin) / 3);
  padding-left: var(--margin);
}

.api-documentation-overview p {
  font-family: var(--ftitle);
  font-weight: 100;
  font-size: var(--fsize);
}

/* search */
#search,
#search_desc {
  left: calc(var(--mleft) + var(--margin));
  top: 4rem;
  width: calc(100% - var(--mleft) - var(--mright) - var(--margin) * 3);
}

#search_desc {
  left: calc(100% - var(--mright) - var(--margin) * 2);
  width: var(--margin);
}
</style>`.trim();

let cssInner = `<style>
:root {
  --bg: #222;
  --line: #333;
  --text: #bbb;
  --link: #b73;
  --desc: white;
  --ftitle: "Open Sans", "Roboto", Helvetica, Arial, sans-serif;
  --ftext: var(--ftitle);
  --fcode: "PragmataPro", "Menlo", "Lucida Console", Courier, monospace;
  --fsize: .7rem;
  --flheight: 1.5;
  --margin: 15px;
  --mleft: 20%;
  --mleft: 20vw;
  --mright: calc(var(--mleft)/2);
  --mbot: var(--mleft);
}

/* toc */
#toc {
  border: none;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  box-shadow: 0 calc(var(--margin) / 2) calc(var(--margin) * 2) calc(var(--margin) / -2) #000f;
  height: 20px;
  left: var(--mleft);
  opacity: 0;
  position: fixed;
  top: 51px;
  transition: height .2s ease-in-out, opacity .2s ease-in-out;
  width: calc(100% - var(--mleft) - var(--mright));
}

#toc:hover {
  height: calc(100% - var(--mbot));
  opacity: 1;
}

#hint {
  background: var(--line);
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  color: var(--link);
  font-family: var(--ftext);
  font-size: var(--fsize);
  left: calc(var(--mleft) + 10px);
  line-height: 10px;
  margin: 0;
  margin-left: -10px;
  padding: 10px;
  padding-top: 0;
  position: fixed;
  top: 52px;
}

/* sidebar */
.sidebar {
  height: 100%;
  left: 0;
  overflow-y: scroll;
  padding: calc(var(--margin) / 2) var(--margin);
  position: fixed;
  top: 0;
  width: var(--mleft);
}

.sidebar * {
  font-size: var(--fsize);
  line-height: var(--flheight);
  list-style: none;
  padding: 0;
}

.sidebar ul ul {
  margin: 0;
  margin-bottom: var(--margin);
}

.sidebar ul ul li {
  font-family: var(--fcode);
}

/* common */
html {
  bottom: 0;
  left: var(--mleft);
  overflow: auto;
  position: fixed;
  top: 92px;
}

body {
  background: var(--bg);
  border: none;
  color: var(--text);
  height: 100%;
  margin: 0;
  padding: 0 var(--mright) 10px 0;
  width: 100%;
  overflow: auto;
}

h1, h2, h3, h4, h5, h6 {
  border: none;
  font-family: var(--ftitle);
  font-weight: 100;
  margin: 0;
}

h1 {font-size: 4rem;}
h2 {font-size: 3.5rem;}
h3 {font-size: 3rem;}
h4 {font-size: 2.5rem;}
h5 {font-size: 2rem;}
h6 {font-size: 1.5rem;}

a {
  color: var(--link);
  text-decoration: none;
}

a:hover {
  border-bottom: 1px solid #b737;
  text-decoration: none;
}

.api-documentation-overview,
.api-documentation-overview p {
  margin: 0;
}

table {
  padding: 0;
  margin: 0;
}

table tr,
table th,
table td,
table tr:nth-child(2n),
.documentation-section {
  border: none;
  background: none;
  padding: 0;
  padding-right: 10px;
}

td, p, li {
  font-family: var(--ftext);
  font-size: 1.2rem;
  font-weight: 300;
  letter-spacing: .02rem;
  line-height: var(--flheight);
}

ul {
  list-style-type: circle;
  padding-left: 1.5rem;
}

.highlight pre,
pre,
code {
  background: var(--line);
  color: var(--text);
  font-family: var(--fcode);
  padding: 0;
  white-space: pre-wrap !important;
}

code:before,
code:after {
  content: "";
}

td:nth-child(2) {
  word-break: break-word;
}

/* index */
section table th:nth-child(1),
.tabcontent table td:nth-child(1) {
  font-family: var(--fcode);
  font-size: var(--fsize);
  font-weight: normal;
  padding-right: var(--margin);
}

section table.api-documentation-overview tr:not(:nth-child(1)) td,
section table.api-documentation-overview tr:not(:nth-child(1)) th {
  padding-bottom: calc(var(--margin) / 2);
}

/* header */
header>h1 {
  background: var(--line);
  border-bottom: 1px solid var(--line);
  color: var(--desc);
  font-size: 2.5rem;
  height: 52px;
  left: var(--mleft);
  margin: 0;
  padding: 0 10px;
  position: fixed;
  top: 0;
  width: calc(100% - var(--mleft) - var(--mright));
}

/* search */
#search,
#search_desc {
  background-color: transparent;
  border: none;
  color: var(--text);
  font-family: var(--fcode);
  font-size: 1rem;
  height: 1rem;
  left: var(--margin);
  outline: none;
  padding: 0;
  position: fixed;
  top: 0;
  width: calc(100% - var(--margin) * 3);
}

#search_desc {
  left: calc(100% - var(--margin) * 2);
  width: var(--margin);
}

.searchresults {
  margin: 0 var(--margin);
}

.searchresults h2 {
  display: none;
}

.searchresults h3 {
  color: var(--text);
  font-size: var(--fsize);
  margin-top: var(--margin);
}

.searchresults h3:first-of-type {
  margin-top: 0;
}

.searchresults ul.results {
  list-style: none;
  margin: 0;
}

.searchresults li {
  font-family: var(--fcode);
  font-size: var(--fsize);
  list-style: none;
}

.searchresults li:last-of-type {
  margin-bottom: calc(var(--margin) * 2);
}

/* items title */
h3:nth-of-type(2),
section[id] table tr th {
  display: none;
}

/* signature */
section[id] table tr:nth-child(1) td code {
  font-family: var(--fcode);
}

/* type */
section[id] table tr:nth-child(2) td,
.note {
  font-family: var(--fcode);
  font-size: var(--fsize);
  margin: 0;
  opacity: .5;
  padding: 0;
}

/* description */
section[id] table tr:nth-child(3) td>p:nth-child(1) {
  color: var(--desc);
  font-family: var(--ftitle);
  font-weight: 100;
  letter-spacing: .05em;
  margin-top: var(--margin);
}

/* tabbar */
div.tab {
  background-color: inherit;
  border: none;
}

div.tab button {
  color: var(--link);
  background-color: inherit;
  padding: calc(var(--margin) / 2) var(--margin);
}

div.tab button:hover {
  background-color: var(--link);
  color: var(--bg);
}

div.tab button.tablinks.active {
  background-color: inherit;
  color: var(--text);
}
</style>`.trim();

(() => {
  if (document.title.match(/^Hammerspoon (.poons )*.ocs$/)) { // index page
    $('body').append(cssInner + cssIndex);
    for (let find of [
        'h3',
      ]) $(find).remove();

    $('th:contains("Resource"), td:contains("Resource")').parents('section').addClass('urls');
    $('#search_desc').attr('title', 'search descriptions');

  }
  else { // inner pages
    for (let find of [
        'Parameters:',
        'Paramters:',
        'Returns:',
        'Notes:',
      ]) $('p:contains(' + find + ')').addClass('note');

    $('h3:contains("API Overview")+ul').wrap('<div class="sidebar"></div>');

    $('body').append(cssInner + '<div id="hint">⌘</div>');
    let toc = document.createElement('iframe'); // add toc menu
    toc.id = 'toc';
    toc.src = $('header>h1>a:first-child').attr('href');
    $('body').append(toc);

    $('#toc').on('load', () => {
      toc = $('#toc').contents();

      toc.find('header').remove();
      toc.find('th:contains("Resource")').parents('section').remove();
      toc.find('html').append(cssInner + cssToc);
      toc.find('head').append('<base target="_top">');
      toc.find('#search_desc').attr('alt', 'Search descriptions');
    });
  }

  // all pages
  for (let find of [
      'API Overview',
      'API Documentation',
    ]) $('h3:contains(' + find + ')').remove();

  $('section:contains("Search descriptions")').contents().filter(function () {
    return this.nodeType === 3;
  }).remove();
  $('#search').focus();

})();