@jseeio/jsee 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -109,8 +109,56 @@ Extra blocks can be provided for further customization
109
109
  - `action` or `button` - Button (its `name` will be passed as a `caller` to the model)
110
110
  - `default` - Default value
111
111
  - `outputs` - Outputs definition
112
+ - `name`* - Name of the output
113
+ - `type`* - Type. Possible types:
114
+ - `object` - JavaScript Object
115
+ - `html` or `svg` - SVG element
116
+ - `code` - Code block
117
+ - `function` - Render function. Rather than returning a value, a model returns a function that JSEE will call passing the container element.
112
118
  - `examples` - List of examples
113
119
  - `autorun` (boolean, default: `false`) - Defines if the script should be evaluated on each input change event
114
120
  - `interval` (number, default: `0`) - Defines the interval between script evaluations (in milliseconds). If set to `0`, the script is evaluated only once.
115
121
 
116
122
  JSEE is a reactive branch of [StatSim](https://statsim.com)'s [Port](https://github.com/statsim/port). It's still work in progress. Expect API changes.
123
+
124
+ # Changelog
125
+
126
+ ## 0.3.4
127
+ ### JSEE:
128
+ - [x] Add `columns` parameter to the `inputs`, `outputs` blocks (making it possible to create multi-column layouts, like simple dashboards)
129
+ - [x] Add `function` output type (for custom renderers which take a container element as an argument)
130
+ - [x] Add `dom-to-image` library for exporting dynamic output blocks to PNG
131
+ - [x] Support for inputs to be set with url parameters (e.g. `?input1=1&input2=2`)
132
+ ### HTML Generator:
133
+ - [x] Add `latex` and table output in the markdown renderer
134
+ - [x] Cache `import` scripts to avoid multiple loads when `--fetch` is used
135
+ - [x] Infer `description` from the markdown and update html `<head>` with it
136
+ - [x] Update `social`, `org`, `ga` blocks
137
+ - [x] Small layout fixes
138
+
139
+ ## 0.3.1
140
+ - [x] Add `download` method to jsee object
141
+ - [x] Add `bin` folder with `cmd.js` for easier project building
142
+
143
+ ## 0.2.9
144
+ - [x] Add examples
145
+ - [x] Add imports
146
+ - [x] Add `caller` field to the model input (can be: `run`, `autorun` or a button name)
147
+ - [x] Add `title` field (for buttons rn)
148
+ - [x] If `display` field is `false` the input is not shown
149
+ - [x] If `autorun` is true, then actually autorun the model initially
150
+
151
+ ## 0.2.8
152
+ - [x] Fix no input case
153
+
154
+ ## 0.2.7
155
+ - [x] Show output when result is `0`
156
+ - [x] Updated style for buttons and inputs
157
+
158
+ ## 0.2.6
159
+ - [x] Tests
160
+ - [x] Load schema from query (loader)
161
+ - [x] Reset button appears only after data change
162
+ - [x] Default input type (`string`)
163
+ - [x] Directly load code when running in a window (not code to text)
164
+ - [x] Passing code directly
package/bin/jsee CHANGED
@@ -1,11 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const minimist = require('minimist')
4
3
  const fs = require('fs')
5
4
  const path = require('path')
5
+ const os = require('os')
6
+ const crypto = require('crypto')
7
+
8
+ const minimist = require('minimist')
6
9
  const jsdoc2md = require('jsdoc-to-markdown')
7
10
  const showdown = require('showdown')
8
- const converter = new showdown.Converter()
11
+ const showdownKatex = require('showdown-katex')
12
+ const converter = new showdown.Converter({
13
+ extensions: [
14
+ showdownKatex({
15
+ throwOnError: true,
16
+ displayMode: true,
17
+ errorColor: '#1500ff',
18
+ output: 'mathml'
19
+ }),
20
+ ],
21
+ tables: true
22
+ })
23
+ showdown.setFlavor('github')
9
24
 
10
25
  // left padding of multiple lines
11
26
  function pad (str, len, start=0) {
@@ -42,13 +57,15 @@ gen(argv)
42
57
 
43
58
  // Adding async here breaks express. TODO: investigate
44
59
  async function gen (argv, returnHtml=false) {
60
+ console.log('argv:', argv)
45
61
  let cwd = process.cwd()
46
62
  let inputs = argv.inputs
47
63
  let outputs = argv.outputs
48
- let imports = argv.imports
49
64
  let description = argv.description
65
+ let version = argv.version
50
66
  let ga = argv.ga
51
67
  let schema
68
+ let descriptionTxt = ''
52
69
  let descriptionHtml = ''
53
70
  let jsdocMarkdown = ''
54
71
 
@@ -88,38 +105,47 @@ async function gen (argv, returnHtml=false) {
88
105
  if (description) {
89
106
  const descriptionMd = fs.readFileSync(path.join(cwd, description), 'utf8')
90
107
  descriptionHtml = converter.makeHtml(descriptionMd)
108
+
109
+ if (descriptionMd.includes('---')) {
110
+ descriptionTxt = descriptionMd
111
+ .split('---')[0]
112
+ .replace(/\n/g, ' ')
113
+ .replace(/\s+/g, ' ')
114
+ .replace(/#/g, '')
115
+ .replace(/\*/g, '')
116
+ .trim()
117
+ }
91
118
  }
92
119
 
93
120
  descriptionHtml += genHtmlFromSchema(schema)
94
121
 
95
- // Generate google analytics code
96
- let gaHtml = ga ? `
97
- <script id="ga-src" async src="https://www.googletagmanager.com/gtag/js?id=${blocks.ga}"></script>
98
- <script id="ga-body">
99
- window['ga-disable-${ga}'] = window.doNotTrack === "1" || navigator.doNotTrack === "1" || navigator.doNotTrack === "yes" || navigator.msDoNotTrack === "1";
100
- window.dataLayer = window.dataLayer || [];
101
- function gtag(){dataLayer.push(arguments);}
102
- gtag('js', new Date());
103
- gtag('config', '${ga}');
104
- </script>
105
- ` : ``
122
+
106
123
 
107
124
  // Generate jsee code
108
125
  let jseeHtml = ''
109
126
  let hiddenElementHtml = ''
110
127
  if (argv.fetch) {
111
- // Fetch the jsee runtime from the CDN or local server
112
- if (argv.version === 'latest') {
113
- const jseeCode = fs.readFileSync(path.join(__dirname, '..', 'dist', 'jsee.runtime.js'), 'utf8')
114
- jseeHtml = `<script>${jseeCode}</script>`
128
+ // Fetch jsee code from the CDN or local server
129
+ let jseeCode
130
+ if (argv.version === 'dev') {
131
+ jseeCode = fs.readFileSync(path.join(__dirname, '..', 'dist', 'jsee.js'), 'utf8')
132
+ } else if (argv.version === 'latest') {
133
+ jseeCode = fs.readFileSync(path.join(__dirname, '..', 'dist', 'jsee.runtime.js'), 'utf8')
115
134
  } else {
116
135
  // Pre-fetch the jsee runtime from the CDN https://cdn.jsdelivr.net/npm/@jseeio/jsee@${argv.version}/dist/jsee.runtime.js
117
- let jseeCode = await fetch(`https://cdn.jsdelivr.net/npm/@jseeio/jsee@${argv.version}/dist/jsee.runtime.js`)
136
+ jseeCode = await fetch(`https://cdn.jsdelivr.net/npm/@jseeio/jsee@${argv.version}/dist/jsee.runtime.js`)
118
137
  jseeCode = await jseeCode.text()
119
- jseeHtml = `<script>${jseeCode}</script>`
120
138
  }
139
+ jseeHtml = `<script>${jseeCode}</script>`
121
140
  // Fetch model files and store them in hidden elements
122
141
  hiddenElementHtml += '<div id="hidden-storage" style="display: none;">'
142
+ if (!schema.model) {
143
+ console.error('No model found in schema')
144
+ process.exit(1)
145
+ }
146
+ if (!Array.isArray(schema.model)) {
147
+ schema.model = [schema.model]
148
+ }
123
149
  for (let m of schema.model) {
124
150
  if (m.url) {
125
151
  const modelCode = fs.readFileSync(path.join(cwd, m.url), 'utf8')
@@ -128,8 +154,42 @@ async function gen (argv, returnHtml=false) {
128
154
  if (m.imports) {
129
155
  for (let i of m.imports) {
130
156
  const importUrl = i.includes('.js') ? i : `https://cdn.jsdelivr.net/npm/${i}`
131
- let importCode = await fetch(importUrl)
132
- importCode = await importCode.text()
157
+
158
+ // Create cache directory if it doesn't exist
159
+ const cacheDir = path.join(os.homedir(), '.cache', 'jsee')
160
+ fs.mkdirSync(cacheDir, { recursive: true })
161
+
162
+ // Create a hash of the importUrl
163
+ const hash = crypto.createHash('sha256').update(importUrl).digest('hex')
164
+ const cacheFilePath = path.join(cacheDir, `${hash}.js`)
165
+
166
+ let importCode
167
+ let useCache = false
168
+
169
+ // Check if cache file exists and is less than 1 day old
170
+ if (fs.existsSync(cacheFilePath)) {
171
+ const stats = fs.statSync(cacheFilePath)
172
+ const mtime = new Date(stats.mtime)
173
+ const now = new Date()
174
+ const ageInDays = (now - mtime) / (1000 * 60 * 60 * 24)
175
+
176
+ if (ageInDays < 1) {
177
+ console.log('Using cached import:', importUrl)
178
+ importCode = fs.readFileSync(cacheFilePath, 'utf8');
179
+ useCache = true;
180
+ }
181
+ }
182
+
183
+ if (!useCache) {
184
+ const response = await fetch(importUrl);
185
+ if (!response.ok) {
186
+ console.error(`Failed to fetch ${importUrl}: ${response.statusText}`);
187
+ process.exit(1);
188
+ }
189
+ importCode = await response.text()
190
+ fs.writeFileSync(cacheFilePath, importCode, 'utf8')
191
+ console.log('Fetched and stored to cache:', importUrl)
192
+ }
133
193
  hiddenElementHtml += `<script type="text/plain" style="display: none;" data-src="${importUrl}">${importCode}</script>`
134
194
  }
135
195
  }
@@ -141,11 +201,74 @@ async function gen (argv, returnHtml=false) {
141
201
  : `<script src="http://localhost:${argv.port}/dist/jsee.runtime.js"></script>`
142
202
  }
143
203
 
204
+ let socialHtml = ''
205
+ let gaHtml = ''
206
+ let orgHtml = ''
207
+
208
+ if (schema.page) {
209
+ if (schema.page.title) {
210
+ title = schema.page.title
211
+ }
212
+ if (schema.page.ga) {
213
+ gaHtml = `
214
+ <script id="ga-src" async src="https://www.googletagmanager.com/gtag/js?id=${schema.page.ga}"></script>
215
+ <script id="ga-body">
216
+ window['ga-disable-${schema.page.ga}'] = window.doNotTrack === "1" || navigator.doNotTrack === "1" || navigator.doNotTrack === "yes" || navigator.msDoNotTrack === "1";
217
+ window.dataLayer = window.dataLayer || [];
218
+ function gtag(){dataLayer.push(arguments);}
219
+ gtag('js', new Date());
220
+ gtag('config', '${schema.page.ga}');
221
+ </script>
222
+ `
223
+ }
224
+
225
+ // Social media links
226
+ if (schema.page.social) {
227
+ // iterate over dict with k, v pairs
228
+ for (let [name, url] of Object.entries(schema.page.social)) {
229
+ switch (name) {
230
+ case 'twitter':
231
+ socialHtml += `<li><a rel="me" href="https://twitter.com/${url}">Twitter</a></li>`
232
+ break
233
+ case 'github':
234
+ socialHtml += `<li><a rel="me" href="https://github.com/${url}">GitHub</a></li>`
235
+ break
236
+ case 'facebook':
237
+ socialHtml += `<li><a rel="me" href="https://www.facebook.com/${url}">Facebook</a></li>`
238
+ break
239
+ case 'linkedin':
240
+ socialHtml += `<li><a rel="me" href="https://www.linkedin.com/company/${url}">LinkedIn</a></li>`
241
+ break
242
+ case 'instagram':
243
+ socialHtml += `<li><a rel="me" href="https://www.instagram.com/${url}">Instagram</a></li>`
244
+ break
245
+ case 'youtube':
246
+ socialHtml += `<li><a rel="me" href="https://www.youtube.com/${url}">YouTube</a></li>`
247
+ break
248
+ default:
249
+ socialHtml += `<li><a rel="me" href="${s.url}">${s.name}</a></li>`
250
+ }
251
+ }
252
+ }
253
+
254
+ if (schema.page.org) {
255
+ orgHtml = `<div class="footer-org"><h4 class="footer-heading"><a href="${schema.page.org.url}">${schema.page.org.name}</a></h4>`
256
+ if (schema.page.org.description) {
257
+ orgHtml += `<p>${schema.page.org.description}</p>`
258
+ }
259
+ orgHtml += '</div>'
260
+ }
261
+
262
+ }
263
+
144
264
  const html = template(schema, {
145
265
  descriptionHtml: pad(descriptionHtml, 8, 1),
266
+ descriptionTxt: descriptionTxt,
146
267
  gaHtml: pad(gaHtml, 2, 1),
147
268
  jseeHtml: jseeHtml,
148
- hiddenElementHtml: hiddenElementHtml
269
+ hiddenElementHtml: hiddenElementHtml,
270
+ socialHtml: pad(socialHtml, 2, 1),
271
+ orgHtml: pad(orgHtml, 2, 1),
149
272
  })
150
273
 
151
274
  if (returnHtml) {
@@ -359,8 +482,11 @@ function genMarkdownFromSchema(schema) {
359
482
 
360
483
  function template(schema, blocks) {
361
484
  let title = 'jsee'
485
+ let url = schema.page.url ? schema.page.url : ''
362
486
  if (schema.title) {
363
487
  title = schema.title
488
+ } else if (schema.page && schema.page.title) {
489
+ title = schema.page.title
364
490
  } else if (schema.model) {
365
491
  if (Array.isArray(schema.model)) {
366
492
  title = schema.model[0].name
@@ -370,28 +496,50 @@ function template(schema, blocks) {
370
496
  }
371
497
 
372
498
  return `<!DOCTYPE html>
499
+
500
+ <!-- Generated by JSEE (https://jsee.org) -->
501
+ <!-- Do not edit this file directly. Edit the source files and run jsee to generate this file. -->
502
+ <!-- Source: ${argv.inputs} -->
503
+ <!-- License: MIT (https://opensource.org/licenses/MIT) -->
504
+
373
505
  <html lang="en">
374
506
  <head>
375
507
  <meta charset="utf-8">
376
508
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
377
509
  <meta name="viewport" content="width=device-width, initial-scale=1">
378
510
  <title>${title}</title>
379
- <meta name="generator" content="Jekyll v4.3.3" />
380
- <meta property="og:title" content="hashr" />
511
+ <meta name="description" content="${blocks.descriptionTxt}">
512
+
513
+ <!-- Open Graph -->
514
+ <meta property="og:title" content="${title}" />
515
+ <meta property="og:description" content="${blocks.descriptionTxt}" />
381
516
  <meta property="og:locale" content="en_US" />
382
- <meta property="og:site_name" content="hashr" />
517
+ <meta property="og:url" content="${url}" />
518
+ <meta property="og:site_name" content="${title}" />
383
519
  <meta property="og:type" content="website" />
520
+
521
+ <!-- Twitter Card -->
384
522
  <meta name="twitter:card" content="summary" />
385
- <meta property="twitter:title" content="hashr" />
386
- <script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","headline":"${title}","name":"${title}","url":"/"}</script>
523
+ <meta name="twitter:title" content="${title}" />
524
+ <meta name="twitter:description" content="${blocks.descriptionTxt}" />
525
+
526
+ <!-- Structured Data -->
527
+ <script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","headline":"${title}","name":"${title}","url":"${url}", "description":"${blocks.descriptionTxt}"}</script>
528
+
529
+ <!-- Canonical Link -->
530
+ <link rel="canonical" href="${url}" />
531
+
532
+ <!-- Favicon -->
387
533
  <link href="data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAEAAAAAAAAAD9/f0AAAAAAPj4+AAMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAAAAAAABERAAAAAAAAEREAAAAAAAAREQABERESABERAAETMzAAEREAARAAAAAREQABEAAAABERAAEQARAAEREAARABEAAREQABEAAAABERAAEQAAAAEREAAREREAAREQABEREQABERAAAAAAAAEREAAAAAAAAREQAAAAAAABHAAwAAwAMAAMADAADAAwAAwAMAAMADAADAAwAAwAMAAMADAADAAwAAwAMAAMADAADAAwAAwAMAAMADAADAAwAA" rel="icon" type="image/x-icon" />
534
+
535
+ <!-- Styles -->
388
536
  <style>
389
537
  /** Main */
390
538
  html { font-size: 16px; }
391
539
  body, h1, h2, h3, h4, h5, h6, p, blockquote, pre, hr, dl, dd, ol, ul, figure { margin: 0; padding: 0; }
392
540
  body { font: 400 16px/1.5 -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Segoe UI Symbol", "Segoe UI Emoji", "Apple Color Emoji", Roboto, Helvetica, Arial, sans-serif; color: #111111; background-color: #fdfdfd; -webkit-text-size-adjust: 100%; -webkit-font-feature-settings: "kern" 1; -moz-font-feature-settings: "kern" 1; -o-font-feature-settings: "kern" 1; font-feature-settings: "kern" 1; font-kerning: normal; display: flex; min-height: 100vh; flex-direction: column; overflow-wrap: break-word; }
393
541
  h1, h2, h3, h4, h5, h6, p, blockquote, pre, ul, ol, dl, figure, .highlight { margin-bottom: 15px; }
394
- hr { margin-top: 30px; margin-bottom: 30px; }
542
+ hr { margin-top: 30px; margin-bottom: 30px; border: 0; border-top: 1px solid #ececec; }
395
543
  main { display: block; /* Default value of display of main element is 'inline' in IE 11. */ }
396
544
  img { max-width: 100%; vertical-align: middle; }
397
545
  figure > img { display: block; }
@@ -438,7 +586,10 @@ function template(schema, blocks) {
438
586
  .site-nav .page-link:not(:last-child) { margin-right: 0; }
439
587
  @media screen and (min-width: 600px) { .site-nav { position: static; float: right; border: none; background-color: inherit; } .site-nav label[for="nav-trigger"] { display: none; } .site-nav .menu-icon { display: none; } .site-nav input ~ .trigger { display: block; } .site-nav .page-link { display: inline; padding: 0; margin-left: auto; } .site-nav .page-link:not(:last-child) { margin-right: 20px; } }
440
588
  .site-footer { border-top: 1px solid #e8e8e8; padding: 30px 0; }
441
- .footer-heading { font-size: 1.125rem; margin-bottom: 15px; }
589
+ .footer-heading { font-size: 1.7rem; line-height: 1.7rem; font-weight: 200; margin-bottom: 5px;}
590
+ .footer-heading a { color: #a2a2a2; text-decoration: none; }
591
+ .footer-heading a:hover { color: #828282; }
592
+ .footer-org p { font-size: 0.65rem; color: #828282; }
442
593
  .feed-subscribe .svg-icon { padding: 5px 5px 2px 0; }
443
594
  .contact-list, .social-media-list, .pagination { list-style: none; margin-left: 0; }
444
595
  .footer-col-wrapper, .social-links { font-size: 0.9375rem; color: #828282; }
@@ -502,7 +653,7 @@ function template(schema, blocks) {
502
653
  <header class="site-header">
503
654
  <div class="wrapper">
504
655
  <span class="site-title">${title}</span>
505
- <button id="download-btn" title="Bundled HTML without external dependencies">Download HTML</button>
656
+ <button id="download-btn" title="Download bundled HTML file without external dependencies to use offline">Download bundle (html)</button>
506
657
  </div>
507
658
  </header>
508
659
  <div class="page-content app-container">
@@ -524,32 +675,12 @@ function template(schema, blocks) {
524
675
  <div class="wrapper">
525
676
  <div class="footer-col-wrapper">
526
677
  <div class="footer-col">
527
- <p>
528
- <a href="https://jsee.io/" class="logo_footer">
529
- <svg width="29mm" height="13mm" viewBox="0 0 29 13" version="1.1" id="svg1274" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" style="width: 50px;">
530
- <defs id="defs1271"/>
531
- <g id="layer1">
532
- <path id="path53650-9-7-8-7-5" style="fill:#000000;fill-opacity:1;stroke-width:0.033443" d="m 15.085048,2.2627646 v 1.7268189 6.9073135 h 1.726792 1.726873 1.726871 V 9.1700919 H 18.538713 16.81184 V 3.9895835 h 1.726873 1.726871 V 2.2627646 H 18.538713 16.81184 Z m 3.453665,3.453624 v 1.7268716 h 1.726871 V 5.7163886 Z"/>
533
- <path id="path53647-5-5-3-6-1" style="fill:#000000;fill-opacity:1;stroke-width:0.033443" d="m 22.001709,2.2627517 v 1.7268184 6.9073269 h 1.726793 1.726871 1.726872 V 9.1700919 H 25.455373 23.728502 V 3.9895701 h 1.726871 1.726872 V 2.2627517 h -1.726872 -1.726871 z m 3.453664,3.4536369 v 1.7268716 h 1.726872 V 5.7163886 Z"/>
534
- <g aria-label="JS" transform="matrix(0.05545656,0,0,0.05597005,-218.22149,96.848185)" id="text9866-2-7-20-0-9-1-4-1" style="font-size:241.925px;fill:#000000;stroke:#0024ee;stroke-width:3.31154">
535
- <g id="path52502-6-4-6-8-3-0" style="fill:#000000">
536
- <path id="path53644-8-2-9-0-8" style="color:#000000;-inkscape-font-specification:'Ubuntu Mono Bold';fill:#000000;stroke:none;stroke-width:3.31155;-inkscape-stroke:none" d="m 4057.5092,-1689.778 -33.3113,-0.027 v 99.6732 c 0,10.8886 -2.3949,18.0118 -6.6855,21.7303 -4.3348,3.7352 -10.0924,5.6444 -17.5448,5.6444 -4.9004,0 -9.717,-1.1428 -14.514,-3.4628 h -0.011 c -4.7842,-2.393 -9.1636,-4.8607 -13.1345,-7.4021 l -1.5765,-1.0103 -12.7499,26.5883 1.0351,0.822 c 4.8358,3.8352 10.7133,7.0544 17.6154,9.6838 7.0314,2.6785 15.6913,3.9804 25.9924,3.9804 9.8334,0 18.2685,-1.3898 25.2967,-4.2345 l 0.016,-0.01 0.016,-0.01 c 6.955,-2.9809 12.6568,-6.9906 17.029,-12.0274 l 0.011,-0.01 c 4.5181,-5.0224 7.7113,-10.908 9.5488,-17.5823 1.98,-6.6083 2.9669,-13.6189 2.9669,-21.0153 z"/>
537
- </g>
538
- <g id="path52504-2-7-1-6-3-5" transform="translate(95.989089,-84.950886)" style="fill:#000000">
539
- <path id="path53638-1-7-4-0-0" style="color:#000000;-inkscape-font-specification:'Ubuntu Mono Bold';fill:#000000;stroke:none;stroke-width:12.5161;-inkscape-stroke:none" d="m 14820.902,-7165.5098 c -61.098,0 -110.108,15.3477 -146.047,46.5274 l -0.04,0.039 h -0.04 c -35.354,31.2211 -53.095,75.0334 -53.095,129.6602 0,27.7074 4.995,51.4357 15.298,70.9336 l 0.04,0.039 0.04,0.045 c 10.052,18.3884 22.693,34.038 37.871,46.8027 l 0.05,0.037 0.05,0.047 c 15.605,12.5992 32.778,22.9927 51.471,31.168 18.277,7.9934 35.956,15.0668 53.053,21.2324 12.58,4.837 25.165,10.284 37.761,16.3379 l 0.116,0.053 0.109,0.053 c 12.38,5.3549 23.522,11.5723 33.449,18.6446 l 0.102,0.076 0.101,0.072 c 9.746,6.3641 17.645,13.7908 23.844,22.3223 5.933,8.165 8.811,17.0897 8.811,27.5117 0,8.4874 -1.396,16.9808 -4.233,25.5703 l -0.05,0.127 -0.04,0.1328 c -2.09,7.3855 -6.277,14.3394 -12.873,21.0312 -6.408,5.904 -15.549,11.0389 -27.597,15.1055 -11.28,3.4051 -26.177,5.2285 -44.551,5.2285 -32.227,0 -59.425,-4.2332 -81.584,-12.4726 -22.161,-8.4662 -41.245,-17.504 -57.227,-27.0625 l -6.488,-3.877 -37.041,103.8457 4.35,2.6699 c 14.574,8.9537 35.758,18.5092 63.875,28.9961 l 0.06,0.037 0.06,0.039 c 28.93,10.1558 66.843,15.0469 113.996,15.0469 70.627,0 124.053,-14.4999 159.64,-44.6446 36.005,-30.6002 54.096,-74.1656 54.096,-128.8164 0,-31.9205 -5.252,-58.6401 -16.158,-80.0176 -10.645,-21.4715 -24.527,-39.3432 -41.582,-53.3886 -16.251,-14.4867 -34.421,-25.8642 -54.418,-34.0684 0,0 -0.04,9e-4 -0.04,-0.037 -18.835,-8.58 -37.086,-16.2605 -54.742,-23.0195 h -0.04 -0.04 c -11.438,-4.253 -23.183,-8.8126 -35.232,-13.6758 -11.18,-4.7508 -21.427,-10.0803 -30.781,-15.9668 -8.553,-6.3562 -15.604,-13.2064 -21.213,-20.541 -5.304,-7.5192 -7.906,-15.8372 -7.906,-25.668 0,-20.2937 6.46,-34.1264 19.728,-43.8281 13.269,-9.7017 34.264,-15.1055 63.244,-15.1055 23.752,0 44.321,3.0022 61.737,8.8614 h 0.04 0.04 c 18.467,6.0121 35.07,13.2006 49.834,21.5449 l 6.312,3.5664 37.239,-99.1895 -4.733,-2.6328 c -18.112,-10.0852 -40.336,-19.0958 -66.734,-27.1504 -26.237,-8.1912 -56.862,-12.2129 -91.906,-12.2129 z" transform="matrix(0.26580544,0,0,0.26336684,98.529211,278.95254)"/>
540
- </g>
541
- </g>
542
- </g>
543
- </svg>
544
- </a>
545
- </p>
678
+ ${blocks.orgHtml}
546
679
  </div>
547
680
  <div class="footer-col">
548
681
  <div class="social-links">
549
682
  <ul class="social-media-list">
550
- <li><a rel="me" href="https://github.com/jseeio/hash" title="jseeio/hash">GitHub</a></li>
551
- <li><a rel="me" href="https://twitter.com/jseeio" title="jseeio">Twitter</a></li>
552
- <li><a rel="me" href="https://www.facebook.com/jseeio" title="jseeio">Facebook</a></li>
683
+ ${blocks.socialHtml}
553
684
  </ul>
554
685
  </div>
555
686
  </div>