solcco
Version:
Documentation generator for Solidity with a literary bent.
827 lines (720 loc) • 17.8 kB
HTML
<html>
<head>
<style>
/* PrismJS 1.22.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+solidity&plugins=line-numbers+autolinker+match-braces */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.1em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.token.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
/* This background color was intended by the author of this theme. */
background: hsla(0, 0%, 100%, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #dd4a68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
pre[class*="language-"].line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}
pre[class*="language-"].line-numbers > code {
position: relative;
white-space: inherit;
}
.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows > span {
display: block;
counter-increment: linenumber;
}
.line-numbers-rows > span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
.token a {
color: inherit;
}
.token.punctuation.brace-hover,
.token.punctuation.brace-selected {
outline: solid 1px;
}
.rainbow-braces .token.punctuation.brace-level-1,
.rainbow-braces .token.punctuation.brace-level-5,
.rainbow-braces .token.punctuation.brace-level-9 {
color: #e50;
opacity: 1;
}
.rainbow-braces .token.punctuation.brace-level-2,
.rainbow-braces .token.punctuation.brace-level-6,
.rainbow-braces .token.punctuation.brace-level-10 {
color: #0b3;
opacity: 1;
}
.rainbow-braces .token.punctuation.brace-level-3,
.rainbow-braces .token.punctuation.brace-level-7,
.rainbow-braces .token.punctuation.brace-level-11 {
color: #26f;
opacity: 1;
}
.rainbow-braces .token.punctuation.brace-level-4,
.rainbow-braces .token.punctuation.brace-level-8,
.rainbow-braces .token.punctuation.brace-level-12 {
color: #e0e;
opacity: 1;
}
</style>
<link href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.css">
<style>
html {
scroll-behavior: smooth;
}
body {
margin: 0;
display: flex;
flex-direction: column;
align-items: stretch;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.32em;
}
h3 {
font-size: 1.17em;
}
.level {
display: flex;
flex-direction: row;
line-height: 1.4;
align-items: baseline;
position: relative;
}
.level:first-child {
padding-top: 3rem;
}
.level.scrollHighlighted {
background: rgb(150 159 228 / 48%);
border-right: 10px solid #515ba27a;
}
.titleLevel .left-background {
padding-top: 2em;
//border-bottom: 4px solid #e5e5ee;
}
.left, .right {
//border: 1px solid red;
}
.left-background {
background: #f5f5ff;
border-right: 1px solid #e5e5ee;
width: 34rem;
position: absolute;
top: 0px;
bottom: 0px;
left: -1px;
z-index: -1;
padding-left: 4em;
}
.hover-background {
border-top: 1px solid rgb(229 229 238 / 0.8);
border-bottom: 1px solid rgb(229 229 238 / 0.3);
right: 0px;
width: auto;
background: rgb(254 255 227 / 0.1);
position: absolute;
top: 0px;
bottom: 0px;
left: -1px;
z-index: -1;
padding-left: 4em;
visibility: hidden;
}
body:not(.bodyFocusing) .level:hover .hover-background {
visibility: visible;
}
.left {
padding-left: 4rem;
width: 34rem;
align-items: stretch;
font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
text-align:right;
flex-shrink: 0;
flex-grow: 0;
}
.level .left {
font-size: 1.1em;
line-height: 1.44;
}
.lineComment {
max-width: 80%;
font-size:0.9em;
text-align: right;
background: white;
display: inline-flex;
flex-direction: column;
//margin-right: calc(-1px);
padding-top: 0.2rem;
padding-bottom: 0.2rem;
border: 1px solid #e5e5ee;
border-right: none;
padding-right: 1rem;
padding-left: 1rem;
margin-bottom: 2px;
margin-left: 1rem;
border-radius: 5px 0px 0px 5px;
}
.lineComment p {
margin: 0
}
.blockComment {
margin-right: 3rem;
text-align: justify;
}
.blockComment *:not(li,code,.katex *) {
margin-top: 0px;
margin-bottom: 1.44em;
}
.blockComment *:last-child:not(li,code,.katex *) {
margin-bottom: 0.72em;
}
.blockComment *:first-child:not(li,code,.katex *) {
margin-top: 0.72em;
}
.blockComment p + ul,
.blockComment p + ol
{
margin-top: -0.72em;
}
.blockComment ul, .blockComment ol {
margin-bottom: 0.72em;
}
// fixme not working like I want
.blockCommont:not(:first-child) {
margin-top: 1em;
}
.blockComment pre {
white-space: pre-wrap;
font-size: 0.84em;
line-height: 1.44;
margin-top: -1.055em;
margin-bottom: 1.055em;
background: hsl(240 21% 102% / 1);
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 0.5em;
padding-right: 2em;
}
p code, ul code, ol code {
background: hsl(240 21% 102% / 1);
padding: 0.2em;
}
.right {
position: relative;
top: 0px;
width: 50%;
//padding-left: 0.5rem;
display: flex;
}
.right, .lines {
line-height: 1.95;
}
.focusing {
background: rgb(254 255 227);
}
.right:hover {
//border: 1px solid blue;
}
.right code {
}
.codewrap {
display: flex;
flex-direction: row;
transition: transform 300ms ease-in-out;
}
.focuser {
align-self: stretch;
flex-shrink: 0;
font-size: 1.3rem;
text-align: center;
display: flex;
flex-direction: row;
justify-content: flex-start;
color: white;
z-index: 1000;
position: absolute;
left: 0;
top: 0;
width: 3.2rem;
height: 100%;
}
.focus-icon {
//line-height: 0.85;
font-size: 1.5rem;
width: 1em;
flex-grow: 0;
flex-shrink: 0;
}
.focus-icon:before, .focus-icon:after {
position: absolute;
text-align: center;
display: block;
left: 0;
width: 1em;
visibility: hidden;
color: #797979;
}
.focus-icon:before {
content:"↡";
top: -1.55em;
pointer-events: none;
}
.focus-icon:after {
content:"↟";
bottom: -1.45em;
pointer-events: none;
}
body:not(.bodyFocusing) .focuser:hover,
body:not(.bodyFocusing) .focusing .focuser {
border-top: 1px dashed #797979;
border-bottom: 1px dashed #797979;
cursor: pointer;
}
body:not(.bodyFocusing) .focuser:hover .focus-icon:before,
body:not(.bodyFocusing) .focuser:hover .focus-icon:after,
body:not(.bodyFocusing) .focusing .focus-icon:before,
body:not(.bodyFocusing) .focusing .focus-icon:after {
visibility: visible;
}
pre {
margin: 0;
}
.right {
position: relative;
}
.lines {
width: content;
flex-shrink: 0;
margin-right: 0;
color: #797979;
text-align: right;
display: flex;
justify-content: flex-end;
margin-right: 1em;
}
.lines pre {
width: 3.5em;
pointer-events: none;
}
body {
display: flex;
flex-direction: row;
}
nav {
width: 22em;
flex-shrink: 0;
background: hsl(240 47% 17% / 1);
position: sticky;
top: 0px;
font-size: 0.9em;
padding-top: 3rem;
padding-bottom: 3rem;
height: calc(100vh - 6rem);
font-family: 'Lato', sans-serif;
background: #f5f5ff;
overflow-y: auto;
}
nav a {
color: hsl(240 82% 98% / 1);
color: black;
display: block;
text-decoration: none;
line-height: 1;
padding-left: 3rem;
}
nav a:hover {
background: white;
}
nav a.highlight {
background: white;
}
nav a.toc-file:hover {
background: black;
}
.toc-file {
font-family: monospace;
font-size: 1.3em;
padding-top: 0.7em;
padding-bottom: 0.6em;
border-top: 1px solid #e5e5ee;
border-bottom: 1px solid #e5e5ee;
background: #37718E;
color: white;
}
* + .toc-file {
margin-top: 2em;
}
.toc-h1 {
font-size: 1.2em;
font-weight: 600;
padding-top: 0.6em;
padding-bottom: 0.55em;
}
.toc-h2 {
font-size: 1em;
padding-left: 3.5rem;
padding-top: 0.4em;
padding-bottom: 0.4em;
}
.toc-h3 + .toc-h2 {
margin-top: .4em;
}
.toc-h3 + .toc-h1,
.toc-h2 + .toc-h1 {
margin-top: .4em;
}
.toc-h3 {
font-size: 0.8em;
padding-left: 6.5rem;
padding-top: 0.4em;
padding-botom: 0.6em;
}
a {
color: black;
}
.filebreak {
width: calc(100% - 4em - 2px);
font-family: monospace;
/*background: #e5e5ee;*/
background: #37718E;
color: white;
text-align: left;
font-size: 1.18em ;
padding-top: 0.7em;
padding-bottom: 0.6em;
line-height: 1 ;
border-top: 1px solid #e5e5ee;
border-bottom: 1px solid #e5e5ee;
}
.katex {
font-size: 1em;
}
</style>
<script>
/* Bounds of DOM element, including margin */
let bounds = (el,wsy) => {
const rect = el.getBoundingClientRect();
const style = getComputedStyle(el);
return {
top: wsy + rect.top - parseInt(style.marginTop),
bottom: wsy + rect.bottom + parseInt(style.marginBottom)
};
};
window.addEventListener('DOMContentLoaded', () => {
/* For future reference. The current TOC highlight fails when you scroll up into a no-headings zone. Then the highlighted heading is the one below the bottom of the viewport; it should be the one above the top of the viewport. A more complete decision tree for future implementation:
* have an array of all heading elements, and they know their position in the array
* have a pointer to "lowest heading above viewport lower edge ("the fold").
* keep set of visible elements
* when an element comes in or out of the set, run:
lowestAboveFold = i
point = lower above fold
for entry in entries
if entry.out
if entry.too_low
if point below or is entry
point = entry.prev
else ()
else (entry.too_high)
if nobody_visible () [???]
else () [???]
else (entry.in)
if point above or is entry
point = entry
*/
/* Keep roughly track of currently viewed section, highlight corresponding toc in nav */
const visibleHeadings = new Set();
const observer = new IntersectionObserver(entries => {
for (const entry of entries)
visibleHeadings[entry.isIntersecting ? 'add' : 'delete'](entry.target);
}, {threshold:0});
const headingsSelector = Array.from({length: {{level}} }, (_,i) => `h${i+1}`).join(', ');
const headings = document.querySelectorAll(headingsSelector);
for (const heading of headings) observer.observe(heading);
let curHeading = null;
window.addEventListener('scroll', e => {
let minBelow = [Infinity,null];
for (const heading of visibleHeadings) {
const b = heading.getBoundingClientRect().bottom;
if (b < minBelow[0]) minBelow = [b,heading];
}
if (minBelow[1] !== curHeading) {
if (minBelow[1] && curHeading) {
document.querySelector(`a[href="#${curHeading.id}"]`).classList.remove('highlight');
}
if (minBelow[1]) {
curHeading = minBelow[1];
document.querySelector(`a[href="#${curHeading.id}"]`).classList.add('highlight');
}
}
});
/* Initialize cache _translate to 0 */
for (const focuser of document.querySelectorAll('.codewrap')) {
focuser._translate = 0;
}
/* Loop through all codewraps. Treat codewraps before t (which is a codewrap)
* in reverse order. Stack codewraps above and below t. */
const focus = (t) => {
const wsy = window.scrollY; // cache value for performance, big difference in chrome
let isBefore = true;
const tBounds = bounds(t,wsy);
let prevBottom = tBounds.bottom - t._translate;
let prevTop = tBounds.top - t._translate;
t._translate = 0;
let befores = [];
// apply changes after t from t downwards
for (const cur of document.querySelectorAll(".codewrap")) {
if (cur === t) {
isBefore = false;
} else if (isBefore) {
befores.push(cur);
} else {
const cBounds = bounds(cur,wsy);
const _translate = prevBottom - cBounds.top;
cur._translate = cur._translate + _translate;
prevBottom = prevBottom + (cBounds.bottom - cBounds.top);
}
}
// apply changes before t from t upwards
let cur;
while ((cur = befores.pop())) {
const cBounds = bounds(cur,wsy);
const _translate = prevTop - cBounds.bottom;
cur._translate = cur._translate + _translate;
prevTop = prevTop - (cBounds.bottom - cBounds.top);
}
// batch changes after reading layout to avoid layout thrashing
for (const cur of document.querySelectorAll('.codewrap')) {
cur.style.transform = `translate(0px,${cur._translate}px)`;
}
};
/* Stop focusing */
let currentFocuser;
const defocus = () => {
currentFocuser.parentNode.classList.remove("focusing");
document.body.classList.remove('bodyFocusing');
currentFocuser = undefined;
for (const t of document.querySelectorAll(".codewrap")) {
t.style.transform = "translate(0px,0px)";
t._translate = 0;
}
};
/* Defocus when clicking anywhere and currently in focus */
document.body.addEventListener('click', e => {
if (currentFocuser) defocus();
});
/* Focus when clicking a focuser. Disabled when in focus. */
for (const focuser of document.querySelectorAll('.focuser')) {
focuser.addEventListener('click', e => {
if (currentFocuser) return;
currentFocuser = e.currentTarget;
focus(currentFocuser.parentNode.querySelector('.codewrap'));
currentFocuser.parentNode.classList.add("focusing");
document.body.classList.add('bodyFocusing');
e.stopPropagation();
});
}
/* Avoid horizontal scrolling when clicking on internal anchors */
let scrollHighlighted = null;
const doScroll = target => target.scrollIntoView({behavior: "auto", block: "start", inline: "end"});
for (const anchor of document.querySelectorAll("a[href^='#']")) {
anchor.addEventListener('click', e => {
e.preventDefault();
history.pushState(null, null, anchor.getAttribute('href'));
// Must use [id=] syntax instead of # syntax to escape forward slash in anchor name.
const target = document.querySelector(`[id='${anchor.getAttribute("href").slice(1)}']`);
if (scrollHighlighted) {
scrollHighlighted.classList.remove('scrollHighlighted');
}
scrollHighlighted = target.closest('.level');
if (scrollHighlighted) {
doScroll(scrollHighlighted);
scrollHighlighted.classList.add('scrollHighlighted');
} else {
doScroll(target);
}
});
};
});
</script>
</head>
<body>
<nav>
{{#each toc}}
<a href="#{{slug}}" class="toc-{{tag}}">{{title}}</a>
{{/each}}
</nav>
<main>
{{#each packedFiles}}
<div class="level titleLevel">
<div class="left-background"></div>
<div id="{{fileSlug}}" class="left filebreak">{{file}}</div>
</div>
{{#each packedResults}}
<div class="level">
<div class="left-background"></div>
<div class="hover-background"></div>
<div class="left">
{{#if lineComment}}
<div class="lineComment">{{{lineComment}}}</div>
{{/if}}
{{#if blockComment}}
<div class="blockComment">{{{blockComment}}}</div>
{{/if}}
</div>
<code class="right solidity">
<div class="codewrap">
<code class="lines"><pre>{{{lines}}}</pre></code>
<pre>{{{code}}}</pre>
</div>
<div class="focuser">
<div class="focus-icon"><!--⥮--></div>
<div class="warning-overlay"></div>
</div>
</code>
</div>
{{/each}}
{{/each}}
</main>
</body>
</html>