pinstripe 0.12.0 → 0.13.0

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.
@@ -352,7 +352,7 @@ Adapter.register('mysql').include({
352
352
  },
353
353
 
354
354
  async first(options = {}){
355
- return (await this.all({ ...options, limit: Sql.fromString('0, 1') })).pop();
355
+ return (await this.all({ ...options, limit: Sql.fromString('1'), offset: Sql.fromString('0') })).pop();
356
356
  },
357
357
 
358
358
  async count(options = {}){
@@ -506,9 +506,18 @@ Adapter.register('mysql').include({
506
506
  if(options.limit){
507
507
  out.push(this.renderSql` limit ${options.limit}`);
508
508
  }
509
- } else if(joinRoot._limit) {
510
- const { page, pageSize } = joinRoot._limit;
511
- out.push(this.renderSql` limit ${(page - 1) * pageSize}, ${pageSize}`);
509
+ } else if(joinRoot._pagination) {
510
+ const { pageSize } = joinRoot._pagination;
511
+ out.push(this.renderSql` limit ${pageSize}`);
512
+ }
513
+
514
+ if(options.hasOwnProperty('offset')){
515
+ if(options.offset){
516
+ out.push(this.renderSql` offset ${options.offset}`);
517
+ }
518
+ } else if(joinRoot._pagination || joinRoot._skipCount) {
519
+ const { page = 1, pageSize = 10 } = joinRoot._pagination || {};
520
+ out.push(this.renderSql` offset ${((page - 1) * pageSize) + joinRoot._skipCount}`);
512
521
  }
513
522
 
514
523
  return this.renderSql`${out}`;
@@ -559,10 +568,16 @@ Adapter.register('mysql').include({
559
568
  out.push(this.renderSql` order by ${this._orderBySql}`);
560
569
  }
561
570
 
562
- if(this._limit) {
563
- const { page, pageSize } = this._limit;
564
- out.push(this.renderSql` limit ${(page - 1) * pageSize}, ${pageSize}`);
571
+ if(this._pagination) {
572
+ const { pageSize } = this._pagination;
573
+ out.push(this.renderSql` limit ${pageSize}`);
565
574
  }
575
+
576
+ if(this._pagination || this._skipCount) {
577
+ const { page = 1, pageSize = 10 } = this._pagination || {};
578
+ out.push(this.renderSql` offset ${((page - 1) * pageSize) + this._skipCount}`);
579
+ }
580
+
566
581
  return this._database.renderSql`${out}`;
567
582
  }
568
583
  }
@@ -582,8 +597,6 @@ const TYPE_TO_COLUMN_TYPE_MAP = {
582
597
  integer: "int(11)",
583
598
  string: "varchar(255)",
584
599
  text: "longtext",
585
- time: "time",
586
- timestamp: "datetime"
587
600
  };
588
601
 
589
602
  const COLUMN_TYPE_TO_TYPE_MAP = (() => {
@@ -1,7 +1,7 @@
1
1
 
2
2
  import sqlite from 'sqlite3';
3
3
  import * as crypto from 'crypto';
4
- import { unlink } from 'fs';
4
+ import { existsSync, unlink } from 'fs';
5
5
  import { promisify } from 'util';
6
6
 
7
7
  import { Adapter } from '../adapter.js';
@@ -14,14 +14,15 @@ import { Table } from '../table.js';
14
14
  import { Row } from '../row.js';
15
15
 
16
16
  let schemaCache = {};
17
+ let connection;
17
18
 
18
19
  Adapter.register('sqlite').include({
19
20
  get connection(){
20
- if(!this._connection){
21
+ if(!connection){
21
22
  const { filename } = this.config;
22
- this._connection = new sqlite.Database(filename);
23
+ connection = new sqlite.Database(filename);
23
24
  }
24
- return this._connection;
25
+ return connection;
25
26
  },
26
27
 
27
28
  escapeValue(value){
@@ -51,13 +52,15 @@ Adapter.register('sqlite').include({
51
52
  },
52
53
 
53
54
  async drop() {
54
- await new Promise((resolve, reject) => {
55
- this._adapter.connection.close(error => error ? reject(error) : resolve());
56
- });
57
- delete this._adapter._connection;
55
+ if(connection){
56
+ await new Promise((resolve, reject) => {
57
+ connection.close(error => error ? reject(error) : resolve());
58
+ });
59
+ connection = undefined;
60
+ }
58
61
  schemaCache = {};
59
62
  this._sessionCache = {};
60
- await promisify(unlink)(this._adapter.config.filename);
63
+ if(existsSync(this._adapter.config.filename)) await promisify(unlink)(this._adapter.config.filename);
61
64
  },
62
65
 
63
66
  async tables(){
@@ -80,9 +83,7 @@ Adapter.register('sqlite').include({
80
83
  },
81
84
 
82
85
  async destroy() {
83
- await new Promise((resolve, reject) => {
84
- this._adapter.connection.close(error => error ? reject(error) : resolve());
85
- });
86
+ // do nothing
86
87
  },
87
88
 
88
89
  async _fetchRows(sql){
@@ -138,7 +139,19 @@ Adapter.register('sqlite').include({
138
139
  while(rows.length){
139
140
  const { _type, ...fields } = rows.shift();
140
141
  if(_type !== undefined){
141
- out.push(await Row.create(_type, this, fields));
142
+ const table = await this[Inflector.pluralize(_type)];
143
+ const mappedFields = {};
144
+ const names = Object.keys(fields);
145
+ while(names.length){
146
+ const name = names.shift();
147
+ const column = await table[name];
148
+ if(column && ['date', 'datetime'].includes(await column.type())){
149
+ mappedFields[name] = new Date(fields[name]);
150
+ } else {
151
+ mappedFields[name] = fields[name];
152
+ }
153
+ }
154
+ out.push(await Row.create(_type, this, mappedFields));
142
155
  } else {
143
156
  out.push(fields);
144
157
  }
@@ -323,7 +336,7 @@ Adapter.register('sqlite').include({
323
336
  },
324
337
 
325
338
  async first(options = {}){
326
- return (await this.all({ ...options, limit: Sql.fromString('0, 1') })).pop();
339
+ return (await this.all({ ...options, limit: Sql.fromString('1'), offset: Sql.fromString('0') })).pop();
327
340
  },
328
341
 
329
342
  async count(options = {}){
@@ -345,6 +358,8 @@ Adapter.register('sqlite').include({
345
358
  type = 'primary_key';
346
359
  } else if(name == 'id'){
347
360
  type = 'alternate_key';
361
+ } else if(name.match(/.+Id$/)){
362
+ type = 'foreign_key';
348
363
  } else {
349
364
  type = COLUMN_TYPE_TO_TYPE_MAP[row.type] || 'string';
350
365
  }
@@ -475,9 +490,18 @@ Adapter.register('sqlite').include({
475
490
  if(options.limit){
476
491
  out.push(this.renderSql` limit ${options.limit}`);
477
492
  }
478
- } else if(joinRoot._limit) {
479
- const { page, pageSize } = joinRoot._limit;
480
- out.push(this.renderSql` limit ${(page - 1) * pageSize}, ${pageSize}`);
493
+ } else if(joinRoot._pagination) {
494
+ const { pageSize } = joinRoot._pagination;
495
+ out.push(this.renderSql` limit ${pageSize}`);
496
+ }
497
+
498
+ if(options.hasOwnProperty('offset')){
499
+ if(options.offset){
500
+ out.push(this.renderSql` offset ${options.offset}`);
501
+ }
502
+ } else if(joinRoot._pagination || joinRoot._skipCount) {
503
+ const { page = 1, pageSize = 10 } = joinRoot._pagination || {};
504
+ out.push(this.renderSql` offset ${((page - 1) * pageSize) + joinRoot._skipCount}`);
481
505
  }
482
506
 
483
507
  return this.renderSql`${out}`;
@@ -527,11 +551,17 @@ Adapter.register('sqlite').include({
527
551
  if(this._orderBySql.length){
528
552
  out.push(this.renderSql` order by ${this._orderBySql}`);
529
553
  }
530
-
531
- if(this._limit) {
532
- const { page, pageSize } = this._limit;
533
- out.push(this.renderSql` limit ${(page - 1) * pageSize}, ${pageSize}`);
554
+
555
+ if(this._pagination) {
556
+ const { pageSize } = this._pagination;
557
+ out.push(this.renderSql` limit ${pageSize}`);
534
558
  }
559
+
560
+ if(this._pagination || this._skipCount) {
561
+ const { page = 1, pageSize = 10 } = this._pagination || {};
562
+ out.push(this.renderSql` offset ${((page - 1) * pageSize) + this._skipCount}`);
563
+ }
564
+
535
565
  return this._database.renderSql`${out}`;
536
566
  }
537
567
  }
@@ -551,8 +581,6 @@ const TYPE_TO_COLUMN_TYPE_MAP = {
551
581
  integer: "integer",
552
582
  string: "varchar",
553
583
  text: "text",
554
- time: "time",
555
- timestamp: "datetime"
556
584
  };
557
585
 
558
586
  const COLUMN_TYPE_TO_TYPE_MAP = (() => {
@@ -7,8 +7,6 @@ export const ALLOWED_TABLE_ADAPTER_COLUMN_TYPES = [
7
7
  'float',
8
8
  'integer',
9
9
  'string',
10
- 'time',
11
- 'timestamp'
12
10
  ];
13
11
 
14
12
  export const TYPE_TO_DEFAULT_VALUE_MAP = {
@@ -32,8 +30,6 @@ export const COLUMN_TYPE_TO_FORM_FIELD_TYPE_MAP = {
32
30
  integer: "number",
33
31
  string: "text",
34
32
  text: "textarea",
35
- time: "datetime-local",
36
- timestamp: "datetime-local"
37
33
  };
38
34
 
39
35
  export const RESERVED_WORDS = [
@@ -108,7 +108,8 @@ export const Table = Base.extend().include({
108
108
  this._fromSql = [this._generateFromSql()];
109
109
  this._whereSql = [];
110
110
  this._orderBySql = [];
111
- this._limit = undefined;
111
+ this._pagination = undefined;
112
+ this._skipCount = 0;
112
113
  }
113
114
  },
114
115
 
@@ -138,12 +139,17 @@ export const Table = Base.extend().include({
138
139
  },
139
140
 
140
141
  paginate(page = 1, pageSize = 10){
141
- this._joinRoot._limit = { page, pageSize };
142
+ this._joinRoot._pagination = { page, pageSize };
142
143
  return this;
143
144
  },
144
145
 
145
146
  clearPagination(){
146
- this._joinRoot._limit = undefined;
147
+ this._joinRoot._pagination = undefined;
148
+ return this;
149
+ },
150
+
151
+ skip(skipCount){
152
+ this._joinRoot._skipCount = skipCount;
147
153
  return this;
148
154
  },
149
155
 
@@ -151,6 +157,7 @@ export const Table = Base.extend().include({
151
157
  return this._database.run`${this._generateSelectSql(options)}`;
152
158
  },
153
159
 
160
+ // can we get rid of this?
154
161
  async forEach(fn){
155
162
  const rows = await this.all();
156
163
  for(let i = 0; i < rows.length; i++){
@@ -231,7 +238,7 @@ export const Table = Base.extend().include({
231
238
  },
232
239
 
233
240
  async toTableAdapter(){
234
- const limit = this._joinRoot._limit;
241
+ const limit = this._joinRoot._pagination;
235
242
  const name = this.constructor.name;
236
243
  let pageCount = 1;
237
244
  let rowCount;
@@ -28,7 +28,7 @@ export const Union = Base.extend().include({
28
28
  });
29
29
  },
30
30
 
31
- initialize(database, collections, orderBySql = [], limit){
31
+ initialize(database, collections, orderBySql = [], pagination, skip = 0){
32
32
  this._adapter = database._adapter;
33
33
  this._database = database
34
34
  this._collections = (collections || this.constructor.tableClasses.map(tableClass => new tableClass(database))).map(collection => {
@@ -38,7 +38,8 @@ export const Union = Base.extend().include({
38
38
  return AsyncPathBuilder.new(collection);
39
39
  });
40
40
  this._orderBySql = [ ...orderBySql ];
41
- this._limit = limit;
41
+ this._pagination = pagination;
42
+ this._skipCount = skip
42
43
  },
43
44
 
44
45
  concat(collection){
@@ -55,12 +56,17 @@ export const Union = Base.extend().include({
55
56
  },
56
57
 
57
58
  paginate(page = 1, pageSize = 10){
58
- this._limit = { page, pageSize };
59
+ this._pagination = { page, pageSize };
59
60
  return this;
60
61
  },
61
62
 
62
63
  clearPagination(){
63
- this._limit = undefined;
64
+ this._pagination = undefined;
65
+ return this;
66
+ },
67
+
68
+ skip(skipCount){
69
+ this._joinRoot._skipCount = skipCount;
64
70
  return this;
65
71
  },
66
72
 
@@ -68,6 +74,7 @@ export const Union = Base.extend().include({
68
74
  return this._database.run`${this._generateSelectSql(options)}`;
69
75
  },
70
76
 
77
+ // can we get rid of this?
71
78
  async forEach(fn){
72
79
  const rows = await this.all();
73
80
  for(let i = 0; i < rows.length; i++){
@@ -91,11 +98,11 @@ export const Union = Base.extend().include({
91
98
  destroy(){},
92
99
 
93
100
  __getMissing(name){
94
- return new Union(this._database, this._collections.map(collection => collection[name]), this._orderBySql, this._limit);
101
+ return new Union(this._database, this._collections.map(collection => collection[name]), this._orderBySql, this._pagination, this._skipCount);
95
102
  },
96
103
 
97
104
  __call(...args){
98
- return new Union(this._database, this._collections.map(collection => collection(...args)), this._orderBySql, this._limit);
105
+ return new Union(this._database, this._collections.map(collection => collection(...args)), this._orderBySql, this._pagination, this._skipCount);
99
106
  },
100
107
 
101
108
  _generateSelectSql: deligateToAdapter('_generateSelectSql'),
@@ -383,7 +383,7 @@ function cleanChildren(){
383
383
  }
384
384
 
385
385
  function clean(){
386
- if(this.is('.progress-bar')) return;
386
+ if(this.is('.ps-progress-bar')) return;
387
387
 
388
388
  [...this.node.childNodes].forEach(node => node._nodeWrapper && clean.call(node._nodeWrapper));
389
389
 
@@ -503,7 +503,7 @@ function insert(virtualNode, referenceChild, returnNodeWrapper = true){
503
503
  } else if(type == '#comment'){
504
504
  node = document.createComment(attributes.value);
505
505
  } else {
506
- node = document.createElement(type);
506
+ node = (type == 'svg' || this.node instanceof SVGElement) ? document.createElementNS('http://www.w3.org/2000/svg', type) : document.createElement(type);
507
507
  Object.keys(attributes).forEach((key) => {
508
508
  node.setAttribute(key, attributes[key]);
509
509
  });
@@ -532,7 +532,7 @@ function normalizeVirtualNode(){
532
532
  }
533
533
 
534
534
  if(this.type == 'body'){
535
- const progressBar = new this.constructor(this, 'div', {class: 'progress-bar', 'data-node-wrapper': 'progress-bar'})
535
+ const progressBar = new this.constructor(this, 'div', {class: 'ps-progress-bar', 'data-node-wrapper': 'progress-bar'})
536
536
  this.children = [
537
537
  progressBar,
538
538
  ...this.children
@@ -16,7 +16,7 @@ export default {
16
16
 
17
17
  get progressBar(){
18
18
  if(!this._progressBar){
19
- this._progressBar = this.descendants.find(node => node.is('.progress-bar'));
19
+ this._progressBar = this.descendants.find(node => node.is('.ps-progress-bar'));
20
20
  }
21
21
  return this._progressBar;
22
22
  },
@@ -10,9 +10,9 @@ export function loadFrame(confirm, target, method, url){
10
10
 
11
11
  if(target == '_overlay'){
12
12
  this.document.descendants.filter(node => node.is('html')).forEach(node => {
13
- node.addClass('has-overlay');
13
+ node.addClass('ps-has-overlay');
14
14
  });
15
- frame = this.document.descendants.find(node => node.is('body')).append(`<div class="overlay" data-node-wrapper="overlay" data-load-on-init="false"></div>`).pop();
15
+ frame = this.document.descendants.find(node => node.is('body')).append(`<div class="ps-overlay" data-node-wrapper="overlay" data-load-on-init="false"></div>`).pop();
16
16
  frame._parent = this;
17
17
  this._overlayChild = frame;
18
18
  } else {
@@ -6,7 +6,7 @@ export default {
6
6
  this.on('click', () => {
7
7
  const { lineContent } = this.data;
8
8
  const { lineNumber } = this.parents.find(n => n.is('[data-line-number]')).data;
9
- const markdownEditor = this.parents.find(n => n.is('.markdown-editor'));
9
+ const markdownEditor = this.parents.find(n => n.is('.ps-markdown-editor'));
10
10
 
11
11
  markdownEditor.replaceLine(lineNumber, lineContent);
12
12
  });
@@ -4,14 +4,14 @@ export default {
4
4
  this.constructor.parent.prototype.initialize.call(this, ...args);
5
5
 
6
6
  const anchorTextarea = this.frame.parent;
7
- const editorTextarea = this.descendants.find(n => n.is('.markdown-editor-text-pane > textarea'));
7
+ const editorTextarea = this.descendants.find(n => n.is('.ps-markdown-editor-text-pane > textarea'));
8
8
 
9
9
  editorTextarea.value = anchorTextarea.value;
10
10
  editorTextarea.focus();
11
11
  editorTextarea.selectionStart = anchorTextarea.selectionStart;
12
12
  editorTextarea.selectionEnd = anchorTextarea.selectionEnd;
13
13
 
14
- const previewFrame = this.frame.descendants.find(n => n.is('.markdown-editor-preview-pane'));
14
+ const previewFrame = this.frame.descendants.find(n => n.is('.ps-markdown-editor-preview-pane'));
15
15
 
16
16
  this.on('submit', () => {
17
17
  const { value } = this.values;
@@ -17,9 +17,9 @@ export default {
17
17
 
18
18
  remove(...args){
19
19
  this.constructor.parent.prototype.remove.call(this, ...args);
20
- if(!this.document.descendants.find(node => node.is('body')).children.filter((child) => child.is('.overlay')).length){
20
+ if(!this.document.descendants.find(node => node.is('body')).children.filter((child) => child.is('.ps-overlay')).length){
21
21
  this.document.descendants.filter(node => node.is('html')).forEach(node => {
22
- node.removeClass('has-overlay');
22
+ node.removeClass('ps-has-overlay');
23
23
  })
24
24
  }
25
25
  }
@@ -1,3 +1,4 @@
1
+ import { View } from '../view.js';
1
2
 
2
3
  export default ({ createEnvironment }) => {
3
4
  return (_params = {}) => createEnvironment(async ({ environment, renderView }) => {
@@ -31,8 +32,18 @@ export default ({ createEnvironment }) => {
31
32
  });
32
33
  };
33
34
 
35
+ const isView = name => !!View.classes[name];
36
+
34
37
  const renderGuardViews = async (renderView, viewName, params) => {
35
38
  const viewNameSegments = viewName != '' ? viewName.split(/\//) : [];
39
+
40
+ const candidateIndexView = [...viewNameSegments, 'index'].join('/');
41
+ const candidateDefaultView = [...viewNameSegments, 'default'].join('/');
42
+
43
+ if(!isView(candidateIndexView) && !isView(candidateDefaultView)){
44
+ viewNameSegments.pop();
45
+ }
46
+
36
47
  const prefixSegments = [];
37
48
  while(true){
38
49
  const out = normalizeResponse(await renderView(prefixSegments.length ? [...prefixSegments, 'guard'].join('/') : 'guard', params));
@@ -0,0 +1,6 @@
1
+
2
+ import { DateTime } from 'luxon';
3
+
4
+ export default () => {
5
+ return (date, format = 'LLL dd, yyyy') => DateTime.fromJSDate(date).toFormat(format);
6
+ };
@@ -70,7 +70,7 @@ export default {
70
70
  });
71
71
 
72
72
  return renderHtml`
73
- <div class="modal" data-node-wrapper="anchor" data-action="remove" data-ignore-events-from-children="true">
73
+ <div class="ps-modal" data-node-wrapper="anchor" data-action="remove" data-ignore-events-from-children="true">
74
74
  <button data-node-wrapper="anchor" data-action="remove"></button>
75
75
  <form method="post" enctype="multipart/form-data" autocomplete="off">
76
76
  <header>
@@ -80,9 +80,9 @@ export default {
80
80
  ${() => {
81
81
  if(otherErrors.length){
82
82
  return renderHtml`
83
- <div class="field">
83
+ <div class="ps-field">
84
84
  ${otherErrors.map(error => renderHtml`
85
- <p class="is-error">${error}</p>
85
+ <p class="ps-is-error">${error}</p>
86
86
  `)}
87
87
  </div>
88
88
  `
@@ -96,31 +96,31 @@ export default {
96
96
  }
97
97
  return renderHtml`
98
98
  <div>
99
- <label>${label}</label>
99
+ <label class="ps-label">${label}</label>
100
100
  ${() => {
101
101
  if(type == 'textarea'){
102
102
  return renderHtml`
103
- <textarea class="${error ? ' is-error' : ''}" name="${name}">${value}</textarea>
103
+ <textarea class="ps-textarea${error ? ' ps-is-error' : ''}" name="${name}">${value}</textarea>
104
104
  `
105
105
  }
106
106
  if(type == 'markdown'){
107
107
  return renderHtml`
108
- <textarea class="${error ? ' is-error' : ''}" name="${name}" data-node-wrapper="anchor" data-target="_overlay" data-href="&_part=markdown-editor">${value}</textarea>
108
+ <textarea class="ps-textarea${error ? ' ps-is-error' : ''}" name="${name}" data-node-wrapper="anchor" data-target="_overlay" data-href="&_part=markdown-editor">${value}</textarea>
109
109
  `
110
110
  }
111
111
  if(type == 'checkbox'){
112
112
  return renderHtml`
113
- <input class="${error ? ' is-error' : ''}" type="checkbox" name="${name}" type="${type}" ${value ? 'checked' : ''} />
113
+ <input class="ps-input${error ? ' ps-is-error' : ''}" type="checkbox" name="${name}" type="${type}" ${value ? 'checked' : ''} />
114
114
  `
115
115
  }
116
116
  return renderHtml`
117
- <input class="${error ? ' is-error' : ''}" name="${name}" type="${type}" value="${value}">
117
+ <input class="ps-input${error ? ' ps-is-error' : ''}" name="${name}" type="${type}" value="${value}">
118
118
  `
119
119
  }}
120
120
  ${() => {
121
121
  if(error){
122
122
  return renderHtml`
123
- <p class="help is-error">${error}</p>
123
+ <p class="ps-is-error">${error}</p>
124
124
  `
125
125
  }
126
126
  }}
@@ -129,8 +129,8 @@ export default {
129
129
  })}
130
130
  </section>
131
131
  <footer>
132
- <button type="submit">${submitTitle}</button>
133
- <button data-node-wrapper="anchor" data-action="remove">${cancelTitle}</button>
132
+ <button class="ps-button" type="submit">${submitTitle}</button>
133
+ <button class="ps-button" data-node-wrapper="anchor" data-action="remove">${cancelTitle}</button>
134
134
  </footer>
135
135
  </form>
136
136
  </div>
@@ -142,13 +142,13 @@ export default {
142
142
  const { value = '' } = params;
143
143
 
144
144
  return renderHtml`
145
- <div class="modal" data-node-wrapper="anchor" data-action="remove" data-ignore-events-from-children="true">
145
+ <div class="ps-modal" data-node-wrapper="anchor" data-action="remove" data-ignore-events-from-children="true">
146
146
  <button data-node-wrapper="anchor" data-action="remove"></button>
147
- <div class="markdown-editor" data-autosubmit="true" data-node-wrapper="markdown-editor">
148
- <div class="markdown-editor-text-pane">
147
+ <div class="ps-markdown-editor" data-autosubmit="true" data-node-wrapper="markdown-editor">
148
+ <div class="ps-markdown-editor-text-pane">
149
149
  <textarea name="value">${value}</textarea>
150
150
  </div>
151
- <div class="markdown-editor-preview-pane" data-url="&_part=markdown-editor-preview" data-node-wrapper="frame"></div>
151
+ <div class="ps-markdown-editor-preview-pane" data-url="&_part=markdown-editor-preview" data-node-wrapper="frame"></div>
152
152
  </div>
153
153
  </div>
154
154
  `;
@@ -0,0 +1,11 @@
1
+
2
+ import { Url } from '../url.js'
3
+
4
+ export default ({ fetch, renderHtml }) => {
5
+ return async (path = '/', params = {}) => {
6
+ const [ status, headers, body ] = await fetch({ ...params, _path: path });
7
+ const url = Url.new('http', 'localhost', 80, path, params).toString().replace(/http:\/\/[^\/]*/, '');
8
+
9
+ return renderHtml`<div data-node-wrapper="frame" data-url="${url}">${renderHtml(body)}</div>`;
10
+ };
11
+ };
@@ -27,11 +27,11 @@ export default ({ overload, renderHtml }) => {
27
27
  return { number, current };
28
28
  });
29
29
  if(pagination.length > 1) return renderHtml`
30
- <nav class="p-pagination pagination">
31
- <ul class="pagination-list mb-4">
30
+ <nav class="ps-pagination">
31
+ <ul>
32
32
  ${pagination.map(({ number, current }) => renderHtml`
33
33
  <li>
34
- <a class="pagination-link${current ? ' is-current' : ''}" href="?page=${number}">${number}</a>
34
+ <a class="${current ? ' ps-is-current' : ''}" href="?page=${number}">${number}</a>
35
35
  </li>
36
36
  `)}
37
37
  </ul>
@@ -23,7 +23,7 @@ export default ({ renderHtml }) => {
23
23
  paragraph.type = 'div';
24
24
  paragraph.attributes = {
25
25
  ...paragraph.attributes,
26
- class: 'frame',
26
+ class: 'ps-frame',
27
27
  'data-node-wrapper': 'frame',
28
28
  'data-url': `/blocks/${name}?args=${encodeURIComponent(args)}`
29
29
  };
@@ -24,16 +24,15 @@ export default ({ overload, renderList, renderHtml, params: { _headers = {} } })
24
24
  if(_headers['x-pinstripe-frame-type'] != 'overlay') return out;
25
25
 
26
26
  return renderHtml`
27
- <div class="modal" data-node-wrapper="anchor" data-action="remove" data-ignore-events-from-children="true">
27
+ <div class="ps-modal" data-node-wrapper="anchor" data-action="remove" data-ignore-events-from-children="true">
28
28
  <button data-node-wrapper="anchor" data-action="remove"></button>
29
- <div>
30
- <header class="modal-card-head">
29
+ <header>
31
30
  <p>${name}</p>
32
31
  </header>
33
- <section class="modal-card-body">
32
+ <div>
34
33
  ${out}
35
- </section>
36
- <footer class="modal-card-foot">
34
+ </div>
35
+ <footer>
37
36
  <button class="button" data-action="remove">Close</button>
38
37
  </footer>
39
38
  </div>
@@ -1,226 +1,15 @@
1
1
 
2
- export default async ({ renderCss, themeConfig }) => renderCss({
3
- get '*'() {
4
- return {
5
- margin: 0,
6
- padding: 0,
7
- color: themeConfig.colors.text,
8
- fontSize: themeConfig.fontSizes.text,
9
- fontWeight: 400,
10
- lineHeight: 1.5,
11
- boxSizing: 'border-box',
12
- fontFamily: themeConfig.fonts.main,
13
- textRendering: 'optimizeLegibility',
14
- textSizeAdjust: '100%',
15
- '-moz-osx-font-smoothing': 'grayscale',
16
- '-webkit-font-smoothing': 'antialiased',
17
- };
18
- },
19
-
20
- 'article, aside, figure, footer, header, hgroup, section': { display: 'block' },
2
+ export default async ({ renderCss }) => renderCss({
21
3
 
22
- get 'code, pre'(){
23
- return {
24
- '-moz-osx-font-smoothing': 'auto',
25
- '-webkit-font-smoothing': 'auto',
26
- 'font-family': themeConfig.fonts.code,
27
- };
28
- },
29
-
30
- get a() {
31
- return {
32
- color: themeConfig.colors.link,
33
- cursor: 'pointer',
34
- textDecoration: 'none',
35
- strong: { color: 'currentColor' },
36
- '&:hover': { color: themeConfig.colors.linkHover }
37
- };
38
- },
39
-
40
- get code() {
41
- return {
42
- backgroundColor: themeConfig.colors.codeBackground,
43
- color: themeConfig.colors.code,
44
- fontSize: themeConfig.fontSizes.code,
45
- fontWeight: themeConfig.fontWeights.code,
46
- padding: themeConfig.space.codePadding
47
- };
48
- },
49
-
50
- get hr() {
51
- return {
52
- backgroundColor: themeConfig.colors.hrBackground,
53
- border: 'none',
54
- display: 'block',
55
- height: themeConfig.sizes.hrHeight,
56
- margin: themeConfig.space.hrMargin
57
- };
4
+ html: {
5
+ fontSize: '62.5%'
58
6
  },
59
7
 
60
- img: {
61
- height: 'auto',
62
- maxWidth: '100%'
8
+ body: {
9
+ fontSize: '1.6rem'
63
10
  },
64
11
 
65
- 'input[type="checkbox"], input[type="radio"]': { verticalAlign: 'baseline' },
66
-
67
- get small() {
68
- return {
69
- fontSize: themeConfig.fontSizes.small
70
- }
71
- },
72
-
73
- span: {
74
- fontStyle: 'inherit',
75
- fontWeight: 'inherit'
76
- },
77
-
78
- get strong() {
79
- return {
80
- color: themeConfig.colors.strong,
81
- fontWeight: themeConfig.fontWeights.strong
82
- }
83
- },
84
-
85
- fieldset: { border: 'none' },
86
-
87
-
88
- get pre() {
89
- return {
90
- '-webkit-overflow-scrolling': 'touch',
91
- backgroundColor: themeConfig.colors.preBackground,
92
- color: themeConfig.colors.pre,
93
- fontSize: themeConfig.fontSizes.pre,
94
- overflowX: 'auto',
95
- padding: themeConfig.space.prePadding,
96
- whiteSpace: 'pre',
97
- wordWrap: 'normal',
98
- code: {
99
- backgroundColor: 'transparent',
100
- color: 'currentColor',
101
- fontSize: themeConfig.fontSizes.preCode,
102
- padding: 0
103
- }
104
- }
105
- },
106
-
107
- 'li + li': { marginTop: '0.25em' },
108
-
109
- 'p, dl, ol, ul, blockquote, pre, table': { '&:not(:last-child)': { marginBottom: '1em' } },
110
-
111
- get 'h1, h2, h3, h4, h5, h6'() {
112
- return {
113
- color: themeConfig.colors.heading,
114
- fontWeight: themeConfig.fontWeights.heading,
115
- lineHeight: themeConfig.lineHeights.heading
116
- };
117
- },
118
-
119
- h1: {
120
- fontSize: '2em',
121
- marginBottom: '0.5em',
122
- '&:not(:first-child)': { marginTop: '1em' }
123
- },
124
-
125
- h2: {
126
- fontSize: '1.75em',
127
- marginBottom: '0.5714em',
128
- '&:not(:first-child)': { marginTop: '1.1428em' }
129
- },
130
-
131
- h3: {
132
- fontSize: '1.5em',
133
- marginBottom: '0.6666em',
134
- '&:not(:first-child)': { marginTop: '1.3333em' }
135
- },
136
-
137
- h4: {
138
- fontSize: '1.25em',
139
- marginBottom: '0.8em'
140
- },
141
-
142
- h5: {
143
- fontSize: '1.125em',
144
- marginBottom: '0.8888em'
145
- },
146
-
147
- h6: {
148
- fontSize: '1em',
149
- marginBottom: '1em'
150
- },
151
-
152
- get blockquote() {
153
- return {
154
- backgroundColor: themeConfig.colors.blockquoteBackground,
155
- padding: themeConfig.space.blockquotePadding
156
- };
157
- },
158
-
159
- ol: {
160
- listStylePosition: 'outside',
161
- marginTop: '1em',
162
- '&:not([type])': { listStyleType: 'decimal' }
163
- },
164
-
165
- ul: {
166
- listStyle: 'disc outside',
167
- marginTop: '1em',
168
- marginLeft: '2em',
169
- marginBottom: '1em',
170
- ul: {
171
- listStyleType: 'circle',
172
- marginTop: '0.5em',
173
- ul: {
174
- listStyleType: 'square',
175
- }
176
- }
177
- },
178
-
179
- figure: {
180
- marginLeft: '2em',
181
- marginRight: '2em',
182
- textAlign: 'center',
183
- '&:not(:first-child)': { marginTop: '2em' },
184
- '&:not(:last-child)': { marginBottom: '2em' },
185
- img: { display: 'inlineBlock' },
186
- figcaption: { fontStyle: 'italic' }
187
- },
188
-
189
- 'sup, sub': { fontSize: '75%' },
190
-
191
- get table() {
192
- return {
193
- width: '100%',
194
-
195
- 'td, th': {
196
- border: themeConfig.borders.tableCell,
197
- borderWidth: themeConfig.borderWidths.tableCell,
198
- padding: themeConfig.space.tableCellPadding,
199
- verticalAlign: 'top',
200
- '&:not([align])': { textAlign: 'inherit' }
201
- },
202
-
203
- th: { color: themeConfig.colors.tableCellHeading },
204
-
205
- thead: {
206
- 'td, th': {
207
- borderWidth: themeConfig.borderWidths.tableHeadCell,
208
- color: themeConfig.colors.tableHeadCell,
209
- }
210
- },
211
-
212
- tfoot: {
213
- 'td, th': {
214
- borderWidth: themeConfig.borderWidths.tableFootCell,
215
- color: themeConfig.colors.tableFootCell,
216
- }
217
- },
218
-
219
- 'tbody tr:last-child': { 'td, th': { borderBottomWidth: 0 } }
220
- }
221
- },
222
-
223
- 'button, *.button': {
12
+ '.ps-button': {
224
13
  '-moz-appearance': 'none',
225
14
  '-webkit-appearance': 'none',
226
15
  display: 'inline-flex',
@@ -228,24 +17,24 @@ export default async ({ renderCss, themeConfig }) => renderCss({
228
17
  verticalAlign: 'top',
229
18
  justifyContent: 'center',
230
19
 
231
- border: '1px solid transparent',
232
- borderRadius: '4px',
20
+ border: '0.1rem solid transparent',
21
+ borderRadius: '0.4rem',
233
22
  boxShadow: 'none',
234
- fontSize: '1rem',
23
+ fontSize: '1.6rem',
235
24
  height: '2.5em',
236
25
  lineHeight: '1.5',
237
26
  position: 'relative',
238
27
 
239
28
  backgroundColor: 'white',
240
29
  borderColor: '#dbdbdb',
241
- borderWidth: '1px',
30
+ borderWidth: '0.1rem',
242
31
  color: '#363636',
243
32
  cursor: 'pointer',
244
33
 
245
- paddingBottom: 'calc(0.5em - 1px)',
34
+ paddingBottom: 'calc(0.5em - 0.1rem)',
246
35
  paddingLeft: '1em',
247
36
  paddingRight: '1em',
248
- paddingTop: 'calc(0.5em - 1px)',
37
+ paddingTop: 'calc(0.5em - 0.1rem)',
249
38
  textAlign: 'center',
250
39
  whiteSpace: 'nowrap',
251
40
 
@@ -270,28 +59,28 @@ export default async ({ renderCss, themeConfig }) => renderCss({
270
59
  }
271
60
  },
272
61
 
273
- "input:not([type='checkbox'])": {
62
+ ".ps-input:not([type='checkbox'])": {
274
63
  '-moz-appearance': 'none',
275
64
  '-webkit-appearance': 'none',
276
65
  alignItems: 'center',
277
- border: '1px solid transparent',
278
- borderRadius: '4px',
66
+ border: '0.1rem solid transparent',
67
+ borderRadius: '0.4rem',
279
68
  boxShadow: 'none',
280
69
  display: 'inline-flex',
281
- fontSize: '1rem',
70
+ fontSize: '1.6rem',
282
71
  height: '2.5em',
283
72
  justifyContent: 'flex-start',
284
73
  lineHeight: '1.5',
285
- paddingBottom: 'calc(0.5em - 1px)',
286
- paddingLeft: 'calc(0.75em - 1px)',
287
- paddingRight: 'calc(0.75em - 1px)',
288
- paddingTop: 'calc(0.5em - 1px)',
74
+ paddingBottom: 'calc(0.5em - 0.1rem)',
75
+ paddingLeft: 'calc(0.75em - 0.1rem)',
76
+ paddingRight: 'calc(0.75em - 0.1rem)',
77
+ paddingTop: 'calc(0.5em - 0.1rem)',
289
78
  position: 'relative',
290
79
  verticalAlign: 'top',
291
80
 
292
81
  backgroundColor: 'white',
293
82
  borderColor: '#dbdbdb',
294
- borderRadius: '4px',
83
+ borderRadius: '0.4rem',
295
84
  color: '#363636',
296
85
 
297
86
  boxShadow: 'inset 0 0.0625em 0.125em rgb(10 10 10 / 5%)',
@@ -318,89 +107,49 @@ export default async ({ renderCss, themeConfig }) => renderCss({
318
107
  },
319
108
  },
320
109
 
321
- textarea: {
322
- border: '1px solid #dbdbdb',
110
+ '.ps-textarea': {
111
+ border: '0.1rem solid #dbdbdb',
323
112
  width: '100%',
324
113
  minHeight: '7em',
325
- borderRadius: '4px',
326
- paddingBottom: 'calc(0.5em - 1px)',
327
- paddingLeft: 'calc(0.75em - 1px)',
328
- paddingRight: 'calc(0.75em - 1px)',
329
- paddingTop: 'calc(0.5em - 1px)',
114
+ borderRadius: '0.4rem',
115
+ paddingBottom: 'calc(0.5em - 0.1rem)',
116
+ paddingLeft: 'calc(0.75em - 0.1rem)',
117
+ paddingRight: 'calc(0.75em - 0.1rem)',
118
+ paddingTop: 'calc(0.5em - 0.1rem)',
330
119
  },
331
120
 
332
- label: {
121
+ '.ps-label': {
333
122
  color: '#363636',
334
123
  display: 'block',
335
- fontSize: '1rem',
124
+ fontSize: '1.6rem',
336
125
  fontWeight: '700',
337
126
  '&:not(:last-child)': { marginBottom: '0.5em' }
338
127
  },
339
128
 
340
- '*.is-error:not(input):not(textarea)': {
129
+ '*.ps-is-error:not(input):not(textarea)': {
341
130
  color: '#f14668',
342
131
  display: 'block',
343
132
  },
344
133
 
345
- '&.has-overlay': { overflow: 'hidden !important' },
346
-
347
- '.card': {
348
- backgroundVolor: 'white',
349
- borderRadius: '0.25rem',
350
- boxShadow: '0 0.5em 1em -0.125em rgb(10 10 10 / 10%), 0 0px 0 1px rgb(10 10 10 / 2%)',
351
- color: '#4a4a4a',
352
- maxWidth: '100%',
353
- position: 'relative',
354
- marginBottom: '2em',
355
-
356
- '> *': {
357
- backgroundColor: 'transparent',
358
- padding: '1.5rem'
359
- },
360
-
361
- '> header': {
362
- backgroundColor: 'transparent',
363
- alignItems: 'stretch',
364
- boxShadow: '0 0.125em 0.25em rgb(10 10 10 / 10%)',
365
- display: 'flex',
366
- alignItems: 'center',
367
- flexGrow: '1',
368
- padding: '0.75rem 1rem',
369
- '> *': {
370
- color: '#363636',
371
- fontWeight: '700'
372
- }
373
- },
374
-
375
- '> footer': {
376
- backgroundColor: 'transparent',
377
- borderTop: '1px solid #ededed',
378
- alignItems: 'stretch'
379
- }
380
- },
381
-
382
- '.container': {
383
- maxWidth: '1020px',
384
- margin: '0 auto 0 auto'
385
- },
134
+ '&.ps-has-overlay': { overflow: 'hidden !important' },
386
135
 
387
- '.default-block': {
388
- borderWidth: '1px',
136
+ '.ps-default-block': {
137
+ borderWidth: '0.1rem',
389
138
  borderStyle: 'dashed',
390
139
  padding: '1em',
391
140
  '> ul > li': { cursor: 'pointer' }
392
141
  },
393
142
 
394
- '.frame': {
143
+ '.ps-frame': {
395
144
  '&:not(:last-child)': { marginBottom: '1em' }
396
145
  },
397
146
 
398
- '.markdown-editor': {
147
+ '.ps-markdown-editor': {
399
148
  display: 'flex',
400
149
  flexDirection: 'row',
401
150
  width: '100%',
402
151
  height: '100%',
403
- maxWidth: '1200px',
152
+ maxWidth: '120.0rem',
404
153
  background: '#fff',
405
154
  zIndex: '1',
406
155
 
@@ -412,7 +161,7 @@ export default async ({ renderCss, themeConfig }) => renderCss({
412
161
  '&-text-pane': {
413
162
  position: 'relative',
414
163
  borderStyle: 'solid',
415
- borderWidth: '0 1px 0 0',
164
+ borderWidth: '0 0.1rem 0 0',
416
165
  borderColor: 'rgb(99, 99, 99)',
417
166
  padding: 0,
418
167
 
@@ -422,7 +171,7 @@ export default async ({ renderCss, themeConfig }) => renderCss({
422
171
  width: '100%',
423
172
  resize: 'none',
424
173
  outline: 'none',
425
- fontSize: '16px',
174
+ fontSize: '1.6rem',
426
175
  fontFamily: 'monospace',
427
176
  padding: '1em'
428
177
  }
@@ -434,7 +183,7 @@ export default async ({ renderCss, themeConfig }) => renderCss({
434
183
  }
435
184
  },
436
185
 
437
- '.modal': {
186
+ '.ps-modal': {
438
187
  display: 'flex',
439
188
  alignItems: 'center',
440
189
  flexDirection: 'column',
@@ -451,16 +200,16 @@ export default async ({ renderCss, themeConfig }) => renderCss({
451
200
  '> button': {
452
201
  background: 'none',
453
202
  position: 'fixed',
454
- right: '20px',
455
- top: '20px',
203
+ right: '2.0rem',
204
+ top: '2.0rem',
456
205
 
457
- height: '32px',
458
- width: '32px',
206
+ height: '3.2rem',
207
+ width: '3.2rem',
459
208
 
460
209
  userSelect: 'none',
461
210
  '-webkit-appearance': 'none',
462
211
  border: 'none',
463
- borderRadius: '9999px',
212
+ borderRadius: '999.9rem',
464
213
  cursor: 'pointer',
465
214
  pointerEvents: 'auto',
466
215
  display: 'inline-block',
@@ -483,24 +232,24 @@ export default async ({ renderCss, themeConfig }) => renderCss({
483
232
  },
484
233
 
485
234
  '&:before': {
486
- height: '2px',
235
+ height: '0.2rem',
487
236
  width: '50%',
488
237
  },
489
238
 
490
239
  '&:after': {
491
240
  height: '50%',
492
- width: '2px',
241
+ width: '0.2rem',
493
242
  }
494
243
  },
495
244
 
496
245
  '> *:not(button)': {
497
- maxHeight: 'calc(100vh - 40px)',
498
- maxWidth: 'calc(100vw - 160px)',
246
+ maxHeight: 'calc(100vh - 4.0rem)',
247
+ maxWidth: 'calc(100vw - 16.0rem)',
499
248
  margin: '0 auto'
500
249
  },
501
250
 
502
251
  '> form': {
503
- minWidth: '640px',
252
+ minWidth: '64.0rem',
504
253
 
505
254
  '> *': {
506
255
  display: 'block',
@@ -508,7 +257,7 @@ export default async ({ renderCss, themeConfig }) => renderCss({
508
257
  flexGrow: '1',
509
258
  flexShrink: '1',
510
259
  overflow: 'auto',
511
- padding: '20px',
260
+ padding: '2.0rem',
512
261
  },
513
262
 
514
263
  '> header, > footer': {
@@ -517,37 +266,37 @@ export default async ({ renderCss, themeConfig }) => renderCss({
517
266
  display: 'flex',
518
267
  flexShrink: '0',
519
268
  justifyContent: 'flex-start',
520
- padding: '20px',
269
+ padding: '2.0rem',
521
270
  position: 'relative'
522
271
  },
523
272
 
524
273
  '> header': {
525
- borderBottom: '1px solid #dbdbdb',
526
- borderTopLeftRadius: '6px',
527
- borderTopRightRadius: '6px',
274
+ borderBottom: '0.1rem solid #dbdbdb',
275
+ borderTopLeftRadius: '0.6rem',
276
+ borderTopRightRadius: '0.6rem',
528
277
 
529
278
  '> *': {
530
279
  color: '#363636',
531
280
  flexGrow: '1',
532
281
  flexShrink: '0',
533
- fontSize: '1.5rem',
282
+ fontSize: '2.4rem',
534
283
  lineHeight: '1'
535
284
  }
536
285
  },
537
286
 
538
287
  '> footer': {
539
- borderBottomLeftRadius: '6px',
540
- borderBottomRightRadius: '6px',
541
- borderTop: '1px solid #dbdbdb'
288
+ borderBottomLeftRadius: '0.6rem',
289
+ borderBottomRightRadius: '0.6rem',
290
+ borderTop: '0.1rem solid #dbdbdb'
542
291
  }
543
292
  }
544
293
  },
545
294
 
546
- '.navbar': {
295
+ '.ps-navbar': {
547
296
  textAlign: 'right'
548
297
  },
549
298
 
550
- '.overlay': {
299
+ '.ps-overlay': {
551
300
  position: 'absolute',
552
301
  top: '0',
553
302
  left: '0',
@@ -556,7 +305,7 @@ export default async ({ renderCss, themeConfig }) => renderCss({
556
305
  zIndex: '1000000'
557
306
  },
558
307
 
559
- '.pagination': {
308
+ '.ps-pagination': {
560
309
  get '> ul'() {
561
310
  return {
562
311
  listStyle: 'none',
@@ -582,24 +331,24 @@ export default async ({ renderCss, themeConfig }) => renderCss({
582
331
  verticalAlign: 'top',
583
332
  justifyContent: 'center',
584
333
 
585
- border: '1px solid transparent',
586
- borderRadius: '4px',
334
+ border: '0.1rem solid transparent',
335
+ borderRadius: '0.4rem',
587
336
  boxShadow: 'none',
588
- fontSize: '1rem',
337
+ fontSize: '1.6rem',
589
338
  height: '2.5em',
590
339
  lineHeight: '1.5',
591
340
  position: 'relative',
592
341
 
593
342
  backgroundColor: 'white',
594
343
  borderColor: '#dbdbdb',
595
- borderWidth: '1px',
344
+ borderWidth: '0.1rem',
596
345
  color: '#363636',
597
346
  cursor: 'pointer',
598
347
 
599
- paddingBottom: 'calc(0.5em - 1px)',
348
+ paddingBottom: 'calc(0.5em - 0.1rem)',
600
349
  paddingLeft: '1em',
601
350
  paddingRight: '1em',
602
- paddingTop: 'calc(0.5em - 1px)',
351
+ paddingTop: 'calc(0.5em - 0.1rem)',
603
352
  textAlign: 'center',
604
353
  whiteSpace: 'nowrap',
605
354
  marginBottom: '2em',
@@ -629,12 +378,12 @@ export default async ({ renderCss, themeConfig }) => renderCss({
629
378
  }
630
379
  },
631
380
 
632
- '.progress-bar': {
381
+ '.ps-progress-bar': {
633
382
  position: 'fixed',
634
383
  display: 'block',
635
384
  top: '0',
636
385
  left: '0',
637
- height: '3px',
386
+ height: '0.3rem',
638
387
  width: '100%',
639
388
  zIndex: '100000',
640
389
 
@@ -646,7 +395,7 @@ export default async ({ renderCss, themeConfig }) => renderCss({
646
395
  display: 'block',
647
396
  top: '0',
648
397
  left: '0',
649
- height: '3px',
398
+ height: '0.3rem',
650
399
  width: '0',
651
400
  background: '#0076ff',
652
401
  transition: `width ${animationDuration}ms ease-out, opacity ${animationDuration / 2}ms ${animationDuration / 2}ms ease-in`,
@@ -13,7 +13,7 @@ export default ({ renderHtml, params: { _path } }) => {
13
13
  .sort()
14
14
 
15
15
  return renderHtml`
16
- <div class="default-block">
16
+ <div class="ps-default-block">
17
17
  <p>Insert block:</p>
18
18
  <ul>
19
19
  ${names.map(name => renderHtml`
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "name": "pinstripe",
4
4
  "description": "Pinstripe is a fullstack JavaScript web framework for Node.js.",
5
- "version": "0.12.0",
5
+ "version": "0.13.0",
6
6
  "author": "Jody Salt",
7
7
  "license": "MIT",
8
8
  "exports": {
@@ -27,6 +27,7 @@
27
27
  "chalk": "^4.1.0",
28
28
  "html-entities": "^2.3.2",
29
29
  "js-yaml": "^4.1.0",
30
+ "luxon": "^2.3.1",
30
31
  "markdown-it": "^12.2.0",
31
32
  "memfs": "^3.2.2",
32
33
  "mime-types": "^2.1.28",
@@ -36,5 +37,5 @@
36
37
  "unionfs": "^4.4.0",
37
38
  "webpack": "^5.39.1"
38
39
  },
39
- "gitHead": "855766e9b5516a28d493c2c45e9684f0f7f59330"
40
+ "gitHead": "47c4af70d05a70d86502cfa877c85f6337560b5a"
40
41
  }