Add dybanamic demo form using preact
This commit is contained in:
parent
53719f7114
commit
b91466fcda
45
assets/sass/_demo.scss
Normal file
45
assets/sass/_demo.scss
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
.demo__actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
> *:not(:last-child) {
|
||||||
|
margin-right: .5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo__times {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo__time-total {
|
||||||
|
font-size: .8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo__time-splits {
|
||||||
|
border-radius: 0;
|
||||||
|
height: .4rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo__time-split {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo__time-split--tokenization {
|
||||||
|
background: $color-accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo__time-split--processing {
|
||||||
|
background: darken($color-accent, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo__time-split--formatting {
|
||||||
|
background: darken($color-accent, 20%);
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
@import "keylighter";
|
@import "keylighter";
|
||||||
@import "sidebar";
|
@import "sidebar";
|
||||||
@import "docs";
|
@import "docs";
|
||||||
|
@import "demo";
|
||||||
|
|
||||||
$footer-height: 60px;
|
$footer-height: 60px;
|
||||||
|
|
||||||
@ -88,6 +89,10 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-not-ready] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
#try-form {
|
#try-form {
|
||||||
padding: 1rem 0;
|
padding: 1rem 0;
|
||||||
color: $foreground;
|
color: $foreground;
|
||||||
@ -115,6 +120,13 @@ body {
|
|||||||
&.visible {
|
&.visible {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
color: $color-accent;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
padding: 5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.d-flex.dual {
|
.d-flex.dual {
|
||||||
|
@ -1,27 +1,15 @@
|
|||||||
import 'bootstrap'
|
if (process.env.NODE_ENV === 'development') {
|
||||||
import TryItForm from "./form"
|
require("preact/debug");
|
||||||
import '@fortawesome/fontawesome-pro/css/all.min.css'
|
}
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
import 'bootstrap'
|
||||||
|
|
||||||
|
// styles
|
||||||
|
import '@fortawesome/fontawesome-pro/css/all.min.css'
|
||||||
import 'typeface-raleway'
|
import 'typeface-raleway'
|
||||||
import '../sass/style.scss'
|
import '../sass/style.scss'
|
||||||
|
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
|
||||||
let $form = $('#try-form');
|
import './try-form'
|
||||||
let $toggle = $('#form-toggle');
|
|
||||||
|
|
||||||
let form = new TryItForm($form, $toggle);
|
|
||||||
|
|
||||||
$toggle.click(() => {
|
|
||||||
form.toggle();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
let $edit = $('#snippet-edit').click(() => {
|
|
||||||
let $snippet = $('#snippet');
|
|
||||||
|
|
||||||
form.source = $snippet.data('source');
|
|
||||||
form.language = $snippet.data('language');
|
|
||||||
|
|
||||||
form.show();
|
|
||||||
});
|
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
export default class TryItForm {
|
|
||||||
private $form: JQuery;
|
|
||||||
private $toggle: JQuery;
|
|
||||||
private $picker: JQuery;
|
|
||||||
|
|
||||||
constructor($form: JQuery, $toggle: JQuery) {
|
|
||||||
this.$form = $form;
|
|
||||||
this.$picker = $form.find('.languages');
|
|
||||||
this.$picker.find('.language').click(e => this.pick(e));
|
|
||||||
this.$form.find('[name="language"]').on('input', e => this.update(e));
|
|
||||||
this.$toggle = $toggle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggle() {
|
|
||||||
if (this.$form.hasClass('visible')) {
|
|
||||||
this.hide();
|
|
||||||
} else {
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public show() {
|
|
||||||
this.$form.slideDown({
|
|
||||||
complete: () => this.$form.addClass('visible')
|
|
||||||
});
|
|
||||||
this.$toggle
|
|
||||||
.addClass('visible')
|
|
||||||
.addClass('active');
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public hide() {
|
|
||||||
this.$form.slideUp({
|
|
||||||
complete: () => this.$form.removeClass('visible')
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$toggle
|
|
||||||
.removeClass('visible')
|
|
||||||
.removeClass('active');
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
get source() {
|
|
||||||
return this.$form.find('[name="source"]').val();
|
|
||||||
}
|
|
||||||
|
|
||||||
set source(value: string) {
|
|
||||||
this.$form.find('[name="source"]').val(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
get language() {
|
|
||||||
return this.$form.find('[name="language"]').val();
|
|
||||||
}
|
|
||||||
|
|
||||||
set language(value: string) {
|
|
||||||
this.$form.find('[name="language"]').val(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set(source: string, language: string) {
|
|
||||||
this.source = source;
|
|
||||||
this.language = language;
|
|
||||||
}
|
|
||||||
|
|
||||||
public submit() {
|
|
||||||
this.$form.find('form').submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
private update(e: JQueryKeyEventObject) {
|
|
||||||
let $this = $(e.currentTarget);
|
|
||||||
let tokens = $this.val()
|
|
||||||
.split(/\b/)
|
|
||||||
.map(x => x.trim())
|
|
||||||
.filter(x => !!x);
|
|
||||||
|
|
||||||
let last: string|boolean = false;
|
|
||||||
|
|
||||||
if (tokens.length) {
|
|
||||||
last = tokens[tokens.length - 1];
|
|
||||||
if (last == '>') {
|
|
||||||
last = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let standalone = tokens.indexOf('>') == -1;
|
|
||||||
this.$picker
|
|
||||||
.toggleClass('embeddable', !standalone)
|
|
||||||
.toggleClass('standalone', standalone);
|
|
||||||
|
|
||||||
this.$picker.find('.language').each((index, elem) => {
|
|
||||||
let $elem = $(elem);
|
|
||||||
let show = !last || (typeof last == 'string' && $elem.text().indexOf(last) !== -1);
|
|
||||||
|
|
||||||
$elem.toggleClass('hidden', !show);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private pick(e: JQueryEventObject) {
|
|
||||||
let $this = $(e.currentTarget);
|
|
||||||
let $selector = this.$form.find('[name="language"]');
|
|
||||||
let input = <HTMLInputElement>$selector[0];
|
|
||||||
let value = input.value;
|
|
||||||
|
|
||||||
let start = input.selectionStart;
|
|
||||||
let end = input.selectionEnd;
|
|
||||||
|
|
||||||
while(start > 0 && value[start-1] != ' ' && start--) {}
|
|
||||||
while(end < value.length && value[end] != ' ' && end++) {}
|
|
||||||
|
|
||||||
input.value = value.substring(0, start) + $this.text().trim() + value.substring(end);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
126
assets/ts/try-form.tsx
Normal file
126
assets/ts/try-form.tsx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import { Fragment, h, render } from "preact";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
|
||||||
|
const formatter = new Intl.NumberFormat(undefined, { maximumFractionDigits: 2 });
|
||||||
|
|
||||||
|
type HighlightFormProps = {
|
||||||
|
onSubmit(code: string, language: string);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HighlightForm = ({ onSubmit }: HighlightFormProps) => {
|
||||||
|
const [code, setCode] = useState<string>("");
|
||||||
|
const [language, setLanguage] = useState<string>("");
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
setCode("");
|
||||||
|
setLanguage("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = () => onSubmit && onSubmit(code, language);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form class="demo__form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="form_source">
|
||||||
|
<span class="far fa-code" aria-hidden="true"/> try it
|
||||||
|
</label>
|
||||||
|
<textarea name="source" class="form-control" id="form_source" rows={ 15 } onInput={ ev => setCode((ev.target as HTMLTextAreaElement).value) }>{ code }</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="form_language" class="col-md-2 col-form-label">
|
||||||
|
<span class="far fa-lightbulb" aria-hidden="true"/> language
|
||||||
|
</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" name="language" id="form_language" class="form-control" required value={ language } onInput={ ev => setLanguage((ev.target as HTMLInputElement).value) }/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div id="language-selector" class="standalone languages">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo__actions">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger" onClick={ handleReset }>
|
||||||
|
<span class="far fa-trash fa-fw" aria-hidden="true"/> reset
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onClick={ handleSubmit }>
|
||||||
|
<span class="far fa-code fa-fw" aria-hidden="true"/> highlight
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loading = () => <div class="loading">
|
||||||
|
<span class="fad fa-spinner-third fa-spin fa-10x" />
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
type HighlightedCodeProps = {
|
||||||
|
highlighted: HighlightedResponse;
|
||||||
|
onClose?(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HighlightedCode = ({ highlighted, onClose }: HighlightedCodeProps) =>
|
||||||
|
<Fragment>
|
||||||
|
<pre class="keylighter" dangerouslySetInnerHTML={{ __html: highlighted.html }}/>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="demo__times">
|
||||||
|
<div class="demo__time-splits">
|
||||||
|
<div class="demo__time-split demo__time-split--tokenization" style={{ width: `${highlighted.times.tokenization / highlighted.times.total * 100}%` }}/>
|
||||||
|
<div class="demo__time-split demo__time-split--processing" style={{ width: `${highlighted.times.processing / highlighted.times.total * 100}%` }}/>
|
||||||
|
<div class="demo__time-split demo__time-split--formatting" style={{ width: `${highlighted.times.formatting / highlighted.times.total * 100}%` }}/>
|
||||||
|
</div>
|
||||||
|
<div class="demo__time-total">
|
||||||
|
Total time: { formatter.format(highlighted.times.total) }ms
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo__actions ml-auto">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onClick={ () => onClose && onClose() }>
|
||||||
|
<span class="far fa-sync fa-fw mr-1" aria-hidden="true"/>
|
||||||
|
try another
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>;
|
||||||
|
|
||||||
|
type DemoState = "form" | "submitting" | "show";
|
||||||
|
type HighlightedResponse = {
|
||||||
|
html: string;
|
||||||
|
times: {
|
||||||
|
total: number;
|
||||||
|
tokenization: number;
|
||||||
|
processing: number;
|
||||||
|
formatting: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const KeylighterDemo = () => {
|
||||||
|
const [state, setState] = useState<DemoState>("form");
|
||||||
|
const [highlighted, setHighlighted] = useState<HighlightedResponse>(null);
|
||||||
|
|
||||||
|
const handleCodeHighlight = async (source, language) => {
|
||||||
|
setState("submitting");
|
||||||
|
setHighlighted(await fetch('/highlight', {
|
||||||
|
credentials: "include",
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ source, language }),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(res => res.json()));
|
||||||
|
setState("show");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="try-form" class="demo">
|
||||||
|
<div class="container">
|
||||||
|
{ state === "form" && <HighlightForm onSubmit={ handleCodeHighlight }/> }
|
||||||
|
{ state === "submitting" && <Loading /> }
|
||||||
|
{ state === "show" && <HighlightedCode highlighted={ highlighted } onClose={ () => setState("form") } /> }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const root = document.getElementById('try-form');
|
||||||
|
render(<KeylighterDemo />, root.parentElement, root);
|
@ -27,13 +27,6 @@ services:
|
|||||||
resource: '../src/Service/*'
|
resource: '../src/Service/*'
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
# controllers are imported separately to make sure they're public
|
|
||||||
# and have a tag that allows actions to type-hint services
|
|
||||||
App\Controller\:
|
|
||||||
resource: '../src/Controller'
|
|
||||||
public: true
|
|
||||||
tags: ['controller.service_arguments']
|
|
||||||
|
|
||||||
# controllers are imported separately to make sure they're public
|
# controllers are imported separately to make sure they're public
|
||||||
# and have a tag that allows actions to type-hint services
|
# and have a tag that allows actions to type-hint services
|
||||||
App\Command\:
|
App\Command\:
|
||||||
@ -43,7 +36,7 @@ services:
|
|||||||
|
|
||||||
App\Listener\KeyLighterVersionListener:
|
App\Listener\KeyLighterVersionListener:
|
||||||
tags:
|
tags:
|
||||||
- { name: kernel.event_listener, event: kernel.request }
|
- { name: kernel.event_listener, event: kernel.request, priority: 4096 }
|
||||||
- { name: kernel.event_listener, event: kernel.response }
|
- { name: kernel.event_listener, event: kernel.response }
|
||||||
|
|
||||||
App\MessageHandler\UpdateKeylighterHandler:
|
App\MessageHandler\UpdateKeylighterHandler:
|
||||||
@ -55,6 +48,8 @@ services:
|
|||||||
Kadet\Highlighter\KeyLighter:
|
Kadet\Highlighter\KeyLighter:
|
||||||
factory: ['@App\Service\KeyLighterVersioner', 'getKeyLighter']
|
factory: ['@App\Service\KeyLighterVersioner', 'getKeyLighter']
|
||||||
|
|
||||||
|
Kadet\Highlighter\Formatter\HtmlFormatter: ~
|
||||||
|
|
||||||
League\CommonMark\Environment:
|
League\CommonMark\Environment:
|
||||||
factory: ['League\CommonMark\Environment', 'createGFMEnvironment']
|
factory: ['League\CommonMark\Environment', 'createGFMEnvironment']
|
||||||
calls:
|
calls:
|
||||||
@ -67,3 +62,10 @@ services:
|
|||||||
|
|
||||||
twig.versioner: '@App\Service\KeyLighterVersioner'
|
twig.versioner: '@App\Service\KeyLighterVersioner'
|
||||||
twig.keylighter: '@App\Twig\KeyLighterTwigAccess'
|
twig.keylighter: '@App\Twig\KeyLighterTwigAccess'
|
||||||
|
|
||||||
|
# controllers are imported separately to make sure they're public
|
||||||
|
# and have a tag that allows actions to type-hint services
|
||||||
|
App\Controller\:
|
||||||
|
resource: '../src/Controller'
|
||||||
|
public: true
|
||||||
|
tags: ['controller.service_arguments']
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"build": "encore production --progress"
|
"build": "encore production --progress"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"preact": "^10.4.0",
|
||||||
"typeface-raleway": "^0.0.75"
|
"typeface-raleway": "^0.0.75"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controller;
|
|
||||||
|
|
||||||
|
|
||||||
use App\Entity\Snippet;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
|
||||||
|
|
||||||
class DemoController extends AbstractController
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @Route("/highlight", name="demo_highlight", methods={"POST"})
|
|
||||||
*/
|
|
||||||
public function highlightAction(Request $request)
|
|
||||||
{
|
|
||||||
$snippet = new Snippet();
|
|
||||||
$snippet->setLanguage($request->get('language'));
|
|
||||||
$snippet->setCode($request->get('source'));
|
|
||||||
|
|
||||||
return $this->forward(sprintf('%s::showAction', SnippetController::class), ['snippet' => $snippet]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
63
src/Controller/HighlightAction.php
Executable file
63
src/Controller/HighlightAction.php
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Kadet\Highlighter\Formatter\HtmlFormatter;
|
||||||
|
use Kadet\Highlighter\KeyLighter;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class HighlightAction
|
||||||
|
{
|
||||||
|
private $keylighter;
|
||||||
|
private $formatter;
|
||||||
|
|
||||||
|
public function __construct(KeyLighter $keylighter, HtmlFormatter $formatter)
|
||||||
|
{
|
||||||
|
$this->keylighter = $keylighter;
|
||||||
|
$this->formatter = $formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/highlight", name="demo_highlight", methods={"POST"})
|
||||||
|
*/
|
||||||
|
public function __invoke(Request $request)
|
||||||
|
{
|
||||||
|
$body = json_decode($request->getContent(), true);
|
||||||
|
|
||||||
|
$language = $this->keylighter->languageByName($body['language']);
|
||||||
|
$source = $body['source'];
|
||||||
|
|
||||||
|
$times = [];
|
||||||
|
|
||||||
|
$tokens = $this->time(function () use ($source, $language) {
|
||||||
|
return $language->tokenize($source);
|
||||||
|
}, $times['tokenization']);
|
||||||
|
|
||||||
|
$tokens = $this->time(function () use ($tokens, $language) {
|
||||||
|
return $language->parse($tokens);
|
||||||
|
}, $times['processing']);
|
||||||
|
|
||||||
|
$formatted = $this->time(function () use ($tokens) {
|
||||||
|
return $this->formatter->format($tokens);
|
||||||
|
}, $times['formatting']);
|
||||||
|
|
||||||
|
$times['total'] = array_sum($times);
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'html' => $formatted,
|
||||||
|
'times' => array_map(function ($time) {
|
||||||
|
return $time * 1000;
|
||||||
|
}, $times),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function time(callable $call, &$time) {
|
||||||
|
$start = microtime(true);
|
||||||
|
$return = $call();
|
||||||
|
$time = microtime(true) - $start;
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
}
|
@ -13,11 +13,6 @@ class KeyLighterVersionListener
|
|||||||
{
|
{
|
||||||
private $versioner;
|
private $versioner;
|
||||||
|
|
||||||
/**
|
|
||||||
* KeyLighterVersionListener constructor.
|
|
||||||
*
|
|
||||||
* @param $versioner
|
|
||||||
*/
|
|
||||||
public function __construct(KeyLighterVersioner $versioner)
|
public function __construct(KeyLighterVersioner $versioner)
|
||||||
{
|
{
|
||||||
$this->versioner = $versioner;
|
$this->versioner = $versioner;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
{% import "macros.twig" as helper %}
|
{% import "macros.twig" as helper %}
|
||||||
{% set current = current is defined ? current : 'demo' %}
|
|
||||||
{% set showForm = showForm|default(false) %}
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
@ -38,11 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="try-form" class="{{ showForm ? 'visible' : 'hidden' }}">
|
<div id="try-form" data-not-ready></div>
|
||||||
<div class="container">
|
|
||||||
{% include 'demo/_form.html.twig' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container" id="content">
|
<div class="container" id="content">
|
||||||
{% block content '' %}
|
{% block content '' %}
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"noImplicitThis": true,
|
"noImplicitThis": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"downlevelIteration": true
|
"downlevelIteration": true,
|
||||||
|
"jsx": "react",
|
||||||
|
"jsxFactory": "h"
|
||||||
},
|
},
|
||||||
"files": ["assets/ts/app.ts"],
|
"files": ["assets/ts/app.ts"],
|
||||||
"include": ["assets/ts/**/*.ts"]
|
"include": ["assets/ts/**/*.ts"]
|
||||||
|
@ -5351,6 +5351,11 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.27, postcss@^7.0.5
|
|||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
supports-color "^6.1.0"
|
supports-color "^6.1.0"
|
||||||
|
|
||||||
|
preact@^10.4.0:
|
||||||
|
version "10.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.0.tgz#90e10264a221690484a56344437a353ffac08600"
|
||||||
|
integrity sha512-34iqY2qPWKAmsi+tNNwYCstta93P+zF1f4DLtsOUPh32uYImNzJY7h7EymCva+6RoJL01v3W3phSRD8jE0sFLg==
|
||||||
|
|
||||||
pretty-error@^2.1.1:
|
pretty-error@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
|
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
|
||||||
|
Loading…
Reference in New Issue
Block a user