From af59d394ae3ff201fa08ef2e1f90182fc62dbc08 Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Mon, 21 Feb 2022 09:32:36 +0100 Subject: [PATCH] Commit --- .DS_Store | Bin 0 -> 8196 bytes .gitignore | 5 +- .vscode/noot.code-workspace | 13 + .vscode/settings.json | 3 + notes/A Cool Note.md | 3 + notes/start.md | 141 ++++ notes/test.md | 1 + server/.vscode/settings.json | 4 + server/server.ts | 74 +++ src/app.ts | 319 --------- src/styles.css | 111 ---- webapp/.DS_Store | Bin 0 -> 6148 bytes webapp/.parcelrc | 6 + package.json => webapp/package.json | 10 +- webapp/src/.DS_Store | Bin 0 -> 6148 bytes webapp/src/app.js | 130 ++++ webapp/src/app.tsx | 173 +++++ webapp/src/commands.js | 38 ++ webapp/src/commands.ts | 47 ++ webapp/src/customtags.js | 4 + webapp/src/customtags.ts | 5 + webapp/src/fs.js | 24 + webapp/src/fs.ts | 38 ++ {src => webapp/src}/index.html | 6 +- webapp/src/lineWrapper.js | 45 ++ webapp/src/lineWrapper.ts | 56 ++ webapp/src/markdown/commands.js | 234 +++++++ {src => webapp/src}/markdown/commands.ts | 0 webapp/src/markdown/index.js | 37 ++ {src => webapp/src}/markdown/index.ts | 0 webapp/src/markdown/markdown.js | 75 +++ {src => webapp/src}/markdown/markdown.ts | 0 webapp/src/parser.js | 57 ++ webapp/src/parser.ts | 60 ++ webapp/src/style.js | 31 + webapp/src/style.ts | 32 + webapp/src/styles.css | 132 ++++ webapp/tsconfig.json | 10 + yarn.lock => webapp/yarn.lock | 811 +++++++++++++---------- 39 files changed, 1937 insertions(+), 798 deletions(-) create mode 100644 .DS_Store create mode 100644 .vscode/noot.code-workspace create mode 100644 .vscode/settings.json create mode 100644 notes/A Cool Note.md create mode 100644 notes/start.md create mode 100644 notes/test.md create mode 100644 server/.vscode/settings.json create mode 100644 server/server.ts delete mode 100644 src/app.ts delete mode 100644 src/styles.css create mode 100644 webapp/.DS_Store create mode 100644 webapp/.parcelrc rename package.json => webapp/package.json (63%) create mode 100644 webapp/src/.DS_Store create mode 100644 webapp/src/app.js create mode 100644 webapp/src/app.tsx create mode 100644 webapp/src/commands.js create mode 100644 webapp/src/commands.ts create mode 100644 webapp/src/customtags.js create mode 100644 webapp/src/customtags.ts create mode 100644 webapp/src/fs.js create mode 100644 webapp/src/fs.ts rename {src => webapp/src}/index.html (72%) create mode 100644 webapp/src/lineWrapper.js create mode 100644 webapp/src/lineWrapper.ts create mode 100644 webapp/src/markdown/commands.js rename {src => webapp/src}/markdown/commands.ts (100%) create mode 100644 webapp/src/markdown/index.js rename {src => webapp/src}/markdown/index.ts (100%) create mode 100644 webapp/src/markdown/markdown.js rename {src => webapp/src}/markdown/markdown.ts (100%) create mode 100644 webapp/src/parser.js create mode 100644 webapp/src/parser.ts create mode 100644 webapp/src/style.js create mode 100644 webapp/src/style.ts create mode 100644 webapp/src/styles.css create mode 100644 webapp/tsconfig.json rename yarn.lock => webapp/yarn.lock (76%) diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fab2a230ec158f35914b637cb344c65f1a40b28d GIT binary patch literal 8196 zcmeHMU2GIp6u#fIv@=tFrcg=;SzW9mr3F@63Khid4^sZD($bdlv(9!0I$=7q?9A?h z4Y4X3|6(-JsEHDd`Y8TIVvHJmGirP=goq~kVB&+K@xjEz7d?0GEYJmf&_FQGP3E4t z=iD>*o^!u5XU{BS3|;xm&5SiL#$>uU)oQ4_NaJ#TUC^YEQ$-Y{&zQ+_>7tiS+iv=T z*%2f1K;(hQ1Ca+J4@4fg8azNbn>YCqd0$AQKJq~1f&Zlk`1>JF7pKXPP6`^lI;aau z0HT$|4jSE49T4cmLz)cfq@aN+JyTQ<2vrf57!c|tkMrq7lOdfHRH!oub%tsA?7wGm2 zfuhJtN~@okNVLRTTN8&{;u9S!=)SGB{qSK$p4+&5&9>Bjd)#p!7Dga^5wIC$MmM6)^2of6qpovj&gAl; zQP<9oJ6=kw9X0IHylwbqr)~FJ_n6+WZyxmd-H7Mr{O(}lutmC@m(sMnXKph|!77+N zq~_I?Z5+z6>2qV(FKSM#yydo@-mQ0?oH28jrmA!5h6kCR+V(vLzS!H3H_X5`GiB7si(QkDb$9mEd~k|g{&>ob<`=0f4NK&V+x z!6HP{kqcnUvfP+lBF-mpYGX1XMhfLAoh_rR)XR2JykyxS_BeZy9c8bx!*thI^c82}N{y-(Bp&Bx3F(21p0j@q*iIQ)G4+ul_F+jD)6K(8c%r#P{f4a@T3D5i1j`(q z`gQ8Um^O`&FNQa$i(*<8pQJ4hQF<8jKM;-;-i~9(&NAMs4_DMX2r|}Gq;w8L{ zSMX{8-FNUo85lQB1tUHz2V=h&{ZkN6zGRjf#1mu3cqUiQ3?&F__fdc~4e!^A|} zsuh&3R<{35x_VUDcgb}1Sh-DQ_6qgO(pQM5Ht_m?{iVPEUzW9_hejTVJaBb*0F^!c zJ^V*N=?6mjws@@_r|WLIc;oXX1r1cF<5M_4D94GO{lk#% “Zef, you keep talking about all these amazing management concepts. You are an inspiration to all. However, what I really want to know is how you apply your enlightened ideas to being a parent!” — Nobody, Ever + +Dear mister or miss “Ever” — if this is in fact your real name. I’m so glad you asked! + +For the rest of you, if you are not a parent, have no plan to be, or have absolutely zero interest in my philosophy of parenting — the latter seems unlikely to me, but I want to call out anyway — feel free to stop reading. + +“So, do I need your permission to stop reading now? I will decide that myself, thank you very much!” + +Thank you for sharing that perspective. However, in your case specifically, I have to insist you keep reading. It’s kids with your independent mindset that we’re trying to raise here. Although, perhaps you already know how to do that. Get in touch. + +---- + +Before we start, why would you even listen to me? Let’s [[be honest]] here, I have no relevant credentials beyond being a dad myself. However, has that ever stopped anybody from doing anything? As any conspiracy theorist would say: you don’t need to take my word for it, do your own research — I’m just asking questions! + +That said, it’s worth knowing I have three kids. All boys. One eight-year old, and five-year-old twins. + +I know what you’re thinking. + +I’m a former academic, I’m not blind to it. My family’s twin boys situation makes for a great **A/B testing opportunity**. So let’s address that right off the bat. + +With two boys of the same age (although one will gladly point out that he was pulled out 2 minutes earlier, so he’s the older one), we could apply one type of experimental parenting technique to one of the twins, and another to the second one. + +Sadly, there are a few reasons that make this a no go: + +1. **Moral:** we have fairly strong sense how we want to raise our kids, and I’m afraid that the argument “sorry, you were the control group” is not going to fly thirty years down the road — as the “B” kid inevitably work through his dysfunctions with his psychologist. +2. **Variance:** even without A/B test our twins are shockingly different. We try to apply a similar approach to parenting with all our kids, still the twins have extremely different behavior. It is unlikely we would be able to tell, thirty years down the line, which parts of their life are screwed up due to our parenting experiment, and which ones are due to how they already were when they popped out. Although, obviously, we will claim full credit for everything if they turn out successful. +3. **Statistical significance:** two boys is a tiny sample size. To get anywhere, we would need a larger sample. Maybe a hundred kids, ideally twin’ed up. My wife has vetoed this idea. + +So no A/B testing with our kids. It is what it is. + +Instead, we will just have to go with our gut here, or make an educated guess. And with that, let me put in a disclaimer: if you decide to take any of this seriously, it’s at your own risk. Don’t come to me in thirty years saying “wow man, we really screwed up my kid with your advice.” Likely I’ll be in the same boat. + +Do your own research. + +---- - + +However, if you’re going to severely limit your own research and just have budgeted one book to read, I would recommend that book to be [Unconditional Parenting](https://amzn.to/3rWwLT4) by *Alfie Kohn*. + +You may remember that I brought up Kohn’s work before. He’s also the guy who wrote [Punished By Rewards](https://amzn.to/3HcBeWd) (which I spoke about at length in [No More Rewards](https://zef.plus/no-more-rewards/)) and [No Contest](https://amzn.to/3LKlgFU) (which I still have to write up). He’s one of my heroes in many ways. He has contrarian ideas, backed up with so much data and research that you can only conclude: oh wow, how could we have been doing this wrong for so long? + +If you have [No More Rewards](https://zef.plus/no-more-rewards/) fresh in your head (as you should), you will actually not be surprised by the parenting approach proposed by Kohn at all. This is to be expected, because, spoiler alert: kids are people too. + +I believe that a lot of challenges people face later in life can be traced back to how they were raised. Everything can be explained by trauma. Read [The Laws of Human Nature](https://amzn.to/3uZIdPz), and you will learn that for a huge amount of “dysfunctions” in people can be traced back to what their context looked like in their early years. Which, incidentally, is another reason to put at least some effort into this whole parenting topic. At least finish this post, is that too much to ask? + +Enough prelude. + +---- + +So, what does Kohn suggest? The way I would frame it (although Kohn does not) is to *work backwards.* Indeed, very Amazonian. Think about what we like our kids to be like when they grow up, and then create a context for them today in which is it is likely they get there. + +What should our kids be like when they’re teenagers, in their twenties and beyond? For many of us, things that will jump to mind will include that they should be **independent**, **creative**, and **confident**. And rich, of course, so they pay us back all that money we invested in them. Do you have any idea what I cost per hour? With interest and taking into account inflation please. + +Great. So let’s see what we can do *now* to help them get there. + +Let’s start with a case study. + +![](IMG_0087.jpeg) + +Meet Leo (picture from a few years back). Leo is the 2-minute-younger twin. Cute, I know. + +What is he doing? He’s showing us a drawing he made. + +How do we respond to this masterpiece? + +What most of us intuitively would do is is say something along the lines of “That’s beautiful!” “Great job!” “Let’s put that on the fridge!” + +We had mentioned that we want our kids to grow up **confident** so this strategy seems to make sense. We help Leo to feel confident by praising his work. You’re awesome, because you drew an awesome bear (I think that’s a bear, at least). + +However, let’s take a step back. Why do you think Leo is showing us this picture? Is he seeking praise? Approval? Does he need *us* (his parents) to feel confident about himself? + +Leo is comfortable. He (rightfully) believes he is loved, and whatever he does won’t change that. He’s a kid, motivated to explore the world and to master his skills. As he progresses, he enjoys sharing this progress with the most important people in his life: us (for now). He can judge himself that he’s making progress (the bear from a month ago looked more like an elephant), he is confident, he has no reason not to be. + +But then, we say “good job, that’s a beautiful drawing!” We offer to put the drawing on the fridge. He may get an ice cream, because we love the drawing that much. + +We’re now changing the game. + +Whereas Leo was purely *intrinsically motivated* before (and **self**-confident as a result), we’ve now (accidentally) taken a step to *extrinsically motivate* him. We have taken a (small) step to make his confidence dependent on external factors: you’re awesome, **because** you drew a bear that was qualified by your parents as “awesome.” He now starts to learn that the world is judging him, and that he should care what people think (it’s coming from his parents after all). And… he’s liking it, because he gets smiles, cheers and ice cream. + +---- + +Let’s recap this whole [intrinsic vs. extrinsic motivation](https://zef.plus/no-more-rewards/) topic we spoke about in the past. + +[Self-determination theory](https://en.wikipedia.org/wiki/Self-determination_theory) says there are two types of motivation with very different properties: + +1. **Intrinsic motivation** is the natural, inherent drive to seek out challenges and new possibilities. Intrinsic motivation is present naturally. It does not need constant reinforcement, it persists unless actively pushed out. +2. **Extrinsic motivation** comes from external sources, for kids this can come in the shape of praise, stickers, ice cream. Compared to intrinsic motivation, extrinsic motivation is easier to control from the outside (hence extrinsic), but it is also short lived — it requires constant *reinforcement*. + +Let this be one of few cases where I express clear judgment: *intrinsic* motivation is the good kind, that’s what we want. In our kids; in the people we work with. Extrinsic motivation is *convenient* (we can easily use it to get people to do what we want), but it’s not long-term sustainable. + +Intrinsic motivation comes from three basic desires that are just as applicable to kids as they are to adults: + +1. **Autonomy** — our ability to have control our own acts and life. +2. **Competence** — our need to control outcomes and experience mastery. +3. **Relatedness** our will to interact with, be connected to others (a sense *belonging* and *purpose*). + +Growing up is all about these things: gaining *autonomy* and *competence* by being able to do more and more things yourself (eating, walking, drawing, writing, reading), all the while being *connected* with the people most important to us (our parents). + +---- + +By praising Leo we are not only at risk replacing intrinsic motivation with extrinsic motivation, we are also reducing his autonomy. Leo’s sense of self worth and confidence becomes a bit more **dependent** on what we (his parents) think. For now he still enjoys drawing, but he starts to be worried whether his parents will like *this* drawing just as much or more than the *previous* one. He liked getting that praise, and seeing all his drawings on the fridge feels good. He wants more of that. It’s kind of addictive. To ensure another reward, he’s likely to play it safe and draw something similar (bye bye **creativity** — which is all about feeling the space to take risk without repercussions). + +Leo makes another drawing. A bit quicker this time, with less effort. The quality is worse (a [known issue with extrinsically motivated work](https://zef.plus/no-more-rewards/)). We don’t respond as enthusiastically as before. Did he do something wrong? Do his parents still love him just as much? + +This doesn’t seem like a great strategy working towards independent, creative, confident children. + +Let’s try a different strategy. A strategy not dependent on rewards. + +---- + +“Oh, you drew a bear and used multiple colors this time! Show me how you did that!” + +We sit with Leo as he shows off his box of crayons, and offer suggestions on how to use the colors to make the next bear look even less like an elephant. + +Absolutely, it is higher effort and time consuming than clamoring “great drawing, here’s an ice cream.” However, Leo still feels important because we spend time with him (boosting his confidence). Also, we don’t make him dependent on our judgment, nor block his creativity. Great! + +Some other scenarios where praise would be an obvious response, but we approach things differently: + +When our older son proudly shared he finished his first *Harry Potter* book (he has read it both in Polish and Dutch, not to brag or anything), we didn’t praise his reading skills. We didn’t reward him for it. Kohn, in his *Punished By Rewards* books cites a piece of research where they tried to “incentivize” reading by giving school kids money rewards for every book they read. The result: they read a lot more… thin books with lots of pictures, with very low recall of what they were about. The kids stopped reading the second the rewards stopped. So it worked, kinda, I suppose? But not really. + +So we don’t do that. When my son fishes a book, we say that we can tell he really enjoys reading, and is getting better at it (mastery), why this matters (purpose), and then buy him the next *Harry Potter* book. Not as a reward, but as a means to support his mastery and joy of reading. + +It’s a struggle. It often feels weird. But we feel it’s right. + +---- + +Let’s put this all in perspective. Does this mean that if you say “good job!” you will turn your kids into compliant zombies that will no longer do anything unless they get a sticker? While Kohn describes one case in his book where kids were “nudged” with external motivators to such a level that they lost all sense of self, this is very extreme. + +Chances are high that you, like most of us, have received your fair share of praise and sticker equivalents growing up. And you turned out alright. For some definition of alright, anyway. + +However, if I were to go out on a limb, I could [ascribe events like the 2008 financial crisis](https://zef.plus/no-more-rewards/) to enough parents and teachers using their gold stars to motivate their kids, training them to be driven by extrinsic motivators like *bonuses* later in life. Could that be a big contributing factor? Did gold stars in school, and parents cheering “nice drawing” result in a financial crisis? I can’t prove that. I’m just asking questions. + +However, what is becoming very visible is that our world is getting more challenging in this sense. For “kids these days” so [much of their self worth](https://www.netflix.com/title/81254224) is determined by how many *likes* they get on facebook. Kids are hammered by social platforms with external motivators. They post a selfie, and stressfully monitor how many hearts they get compared to their friends, and how many comments. How many followers do they have? + +If we can do anything to equip our kids to be resistant to this type of stuff in the future, I’m eager to do it. + +I’m not so naive to believe that I’ve now completely convinced you ought to completely change your approach to parenting tomorrow. Next week is fine too. After that your kids will be doomed though. Just saying. + +Somewhat more seriously, go do your own research… by reading that [Unconditional Parenting](https://amzn.to/3rWwLT4) book. + +No more rewards. Even for our kids. \ No newline at end of file diff --git a/notes/test.md b/notes/test.md new file mode 100644 index 0000000..900591c --- /dev/null +++ b/notes/test.md @@ -0,0 +1 @@ +Sappie \ No newline at end of file diff --git a/server/.vscode/settings.json b/server/.vscode/settings.json new file mode 100644 index 0000000..8675ad5 --- /dev/null +++ b/server/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "deno.enable": true, + "deno.unstable": true +} \ No newline at end of file diff --git a/server/server.ts b/server/server.ts new file mode 100644 index 0000000..070220e --- /dev/null +++ b/server/server.ts @@ -0,0 +1,74 @@ +import * as path from "https://deno.land/std@0.125.0/path/mod.ts"; +import FileInfo = Deno.FileInfo; + +import { Application, Router } from "https://deno.land/x/oak/mod.ts"; +import { oakCors } from "https://deno.land/x/cors@v1.2.0/mod.ts"; +import { readAll } from "https://deno.land/std@0.126.0/streams/mod.ts"; + + +const fsPrefix = '/fs'; +const notesPath = '../notes'; + +const fsRouter = new Router(); + +fsRouter.use(oakCors()); + +fsRouter.get('/', async context => { + const localPath = notesPath; + let fileNames: string[] = []; + for await (const dirEntry of Deno.readDir(localPath)) { + if (dirEntry.isFile) { + fileNames.push(dirEntry.name.substring(0, dirEntry.name.length - path.extname(dirEntry.name).length)); + } + } + context.response.body = JSON.stringify(fileNames); +}); + +fsRouter.get('/:note', async context => { + const noteName = context.params.note; + const localPath = `${notesPath}/${noteName}.md`; + const text = await Deno.readTextFile(localPath); + context.response.body = text; +}); + +fsRouter.options('/:note', async context => { + const localPath = `${notesPath}/${context.params.note}.md`; + const stat = await Deno.stat(localPath); + context.response.headers.set('Content-length', `${stat.size}`); +}) + +fsRouter.put('/:note', async context => { + const noteName = context.params.note; + + const localPath = `${notesPath}/${noteName}.md`; + let file; + try { + file = await Deno.create(localPath); + } catch (e) { + console.error("Error opening file for writing", localPath, e); + context.response.status = 500; + context.response.body = e.message; + return; + } + const result = context.request.body({ type: "reader" }); + const text = await readAll(result.value); + file.write(text); + file.close(); + console.log("Wrote to", localPath) + context.response.body = "OK"; +}); + +const app = new Application(); +app.use(new Router().use(fsPrefix, fsRouter.routes(), fsRouter.allowedMethods()).routes()); +app.use(async (context, next) => { + try { + await context.send({ + root: '../webapp/dist', + index: 'index.html' + }); + } catch { + next(); + } +}); + +await app.listen({ port: 2222 }); diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index f8f6bec..0000000 --- a/src/app.ts +++ /dev/null @@ -1,319 +0,0 @@ -import {markdown} from "./markdown"; -import {commonmark, mkLang} from "./markdown/markdown"; - -import { - Decoration, - DecorationSet, - drawSelection, - dropCursor, - EditorView, - highlightSpecialChars, - keymap, - ViewPlugin, - ViewUpdate -} from '@codemirror/view'; -import {history, historyKeymap} from '@codemirror/history'; -import {foldKeymap} from '@codemirror/fold'; -import {indentOnInput, syntaxTree} from '@codemirror/language'; -import {indentWithTab, standardKeymap} from '@codemirror/commands'; -import {bracketMatching} from '@codemirror/matchbrackets'; -import {closeBrackets, closeBracketsKeymap} from '@codemirror/closebrackets'; -import {searchKeymap} from '@codemirror/search'; -import {autocompletion, completionKeymap} from '@codemirror/autocomplete'; -import {rectangularSelection} from '@codemirror/rectangular-selection'; -import {HighlightStyle, styleTags, Tag, tags as t} from '@codemirror/highlight'; -import {lintKeymap} from '@codemirror/lint'; -import {EditorSelection, EditorState, StateCommand, Transaction} from "@codemirror/state"; -import {Text} from "@codemirror/text"; -import {MarkdownConfig} from "@lezer/markdown"; -import {commonmarkLanguage} from "@codemirror/lang-markdown"; - -const defaultMd = `# Custom Box Design -Some #time ago I (that's @zef.hemel) wrote [No More Boxes](https://zef.me/musing/no-more-boxes/). Let me finally follow up on that and share an approach that I’ve been using opportunistically here and there, primarily for roles that hadn’t been well defined yet. - -Let me start out with a few [[principles]] are: - - Our starting point is that everybody is **different**, and we should _benefit_ from this fact rather than _suppress_ it. The goal is therefore to uncover every person’s [“essence,”](https://zef.me/musing/your-essence/) develop it and optimally integrate it into the larger organization. - - -And fenced - -\`\`\` -Hello -\`\`\` - -## Second lever - -Steve Jobs famously said: - -> It doesn't make sense to hire smart people and then tell them what to do. We hire smart people so they can tell _us_ what to do. -> -> Another thing - -We can adapt this quote to personal development. Here’s how we can formulate this analogy: - -A list: - -* We can adapt this quote to personal development. Here’s how we can formulate this analogy. ANd some other non duplicate text. We can adapt this quote to personal development. Here’s how we can formulate this analogy. We can adapt this quote to personal development. Here’s **how** we can formulate this analogy. -* Another line - -The role of management is to challenge and support people in this process, and provide them with relevant context (e.g. knowledge, experience, connections) they need.` - -const WikiLinkTag = Tag.define(); -const TagTag = Tag.define(); -const MentionTag = Tag.define(); - -let mdStyle = HighlightStyle.define([ - {tag: t.heading1, class: "h1"}, - {tag: t.heading2, class: "h2"}, - {tag: t.link, class: "link"}, - {tag: t.meta, class: "meta"}, - {tag: t.quote, class: "quote"}, - {tag: t.monospace, class: "code"}, - {tag: t.url, class: "url"}, - {tag: WikiLinkTag, class: "wiki-link"}, - {tag: TagTag, class: "tag"}, - {tag: MentionTag, class: "mention"}, - {tag: t.emphasis, class: "emphasis"}, - {tag: t.strong, class: "strong"}, - {tag: t.atom, class: "atom"}, - {tag: t.bool, class: "bool"}, - {tag: t.url, class: "url"}, - {tag: t.inserted, class: "inserted"}, - {tag: t.deleted, class: "deleted"}, - {tag: t.literal, class: "literal"}, - {tag: t.list, class: "list"}, - {tag: t.definition, class: "li"}, - {tag: t.string, class: "string"}, - {tag: t.number, class: "number"}, - {tag: [t.regexp, t.escape, t.special(t.string)], class: "string2"}, - {tag: t.variableName, class: "variableName"}, - {tag: t.comment, class: "comment"}, - {tag: t.invalid, class: "invalid"}, - {tag: t.punctuation, class: "punctuation"} -]); - -function insertMarker(marker: string): StateCommand { - return ({state, dispatch}) => { - const changes = state.changeByRange((range) => { - const isBoldBefore = state.sliceDoc(range.from - marker.length, range.from) === marker; - const isBoldAfter = state.sliceDoc(range.to, range.to + marker.length) === marker; - const changes = []; - - changes.push(isBoldBefore ? { - from: range.from - marker.length, - to: range.from, - insert: Text.of(['']) - } : { - from: range.from, - insert: Text.of([marker]), - }) - - changes.push(isBoldAfter ? { - from: range.to, - to: range.to + marker.length, - insert: Text.of(['']) - } : { - from: range.to, - insert: Text.of([marker]), - }) - - const extendBefore = isBoldBefore ? -marker.length : marker.length; - const extendAfter = isBoldAfter ? -marker.length : marker.length; - - return { - changes, - range: EditorSelection.range(range.from + extendBefore, range.to + extendAfter), - } - }) - - dispatch( - state.update(changes, { - scrollIntoView: true, - annotations: Transaction.userEvent.of('input'), - }) - ) - - return true - }; -} - - -interface WrapElement { - selector: string; - class: string; -} - -function wrapLines(view: EditorView, wrapElements: WrapElement[]) { - let widgets = []; - for (let {from, to} of view.visibleRanges) { - const doc = view.state.doc; - syntaxTree(view.state).iterate({ - from, to, - enter: (type, from, to) => { - const bodyText = doc.sliceString(from, to); - console.log("Enter", type.name, bodyText) - for (let wrapElement of wrapElements) { - if (type.name == wrapElement.selector) { - const bodyText = doc.sliceString(from, to); - // console.log("Found", type.name, "with: ", bodyText); - let idx = from; - for (let line of bodyText.split("\n")) { - widgets.push(Decoration.line({ - class: wrapElement.class, - }).range(doc.lineAt(idx).from)); - idx += line.length + 1; - } - } - } - }, - leave(type, from: number, to: number) { - console.log("Leaving", type.name); - } - }); - } - console.log("All widgets", widgets) - return Decoration.set(widgets); -} - -const lineWrapper = (wrapElements: WrapElement[]) => ViewPlugin.fromClass(class { - decorations: DecorationSet - - constructor(view: EditorView) { - this.decorations = wrapLines(view, wrapElements); - } - - update(update: ViewUpdate) { - if (update.docChanged || update.viewportChanged) { - this.decorations = wrapLines(update.view, wrapElements) - } - } -}, { - decorations: v => v.decorations, -}); - -const WikiLink: MarkdownConfig = { - defineNodes: ["WikiLink"], - parseInline: [{ - name: "WikiLink", - parse(cx, next, pos) { - let match: RegExpMatchArray | null - if (next != 91 /* '[' */ || !(match = /^\[[^\]]+\]\]/.exec(cx.slice(pos + 1, cx.end)))) { - return -1; - } - return cx.addElement(cx.elt("WikiLink", pos, pos + 1 + match[0].length)) - }, - after: "Emphasis" - }] -} - -const AtMention: MarkdownConfig = { - defineNodes: ["AtMention"], - parseInline: [{ - name: "AtMention", - parse(cx, next, pos) { - let match: RegExpMatchArray | null - if (next != 64 /* '@' */ || !(match = /^[A-Za-z\.]+/.exec(cx.slice(pos + 1, cx.end)))) { - return -1; - } - return cx.addElement(cx.elt("AtMention", pos, pos + 1 + match[0].length)) - }, - after: "Emphasis" - }] -} - -const TagLink: MarkdownConfig = { - defineNodes: ["TagLink"], - parseInline: [{ - name: "TagLink", - parse(cx, next, pos) { - let match: RegExpMatchArray | null - if (next != 35 /* '#' */ || !(match = /^[A-Za-z\.]+/.exec(cx.slice(pos + 1, cx.end)))) { - return -1; - } - return cx.addElement(cx.elt("TagLink", pos, pos + 1 + match[0].length)) - }, - after: "Emphasis" - }] -} -const WikiMarkdown = commonmark.configure([WikiLink, AtMention, TagLink, { - props: [ - styleTags({ - WikiLink: WikiLinkTag, - AtMention: MentionTag, - TagLink: TagTag, - }) - ] -}]) - -/// Language support for [GFM](https://github.github.com/gfm/) plus -/// subscript, superscript, and emoji syntax. -export const myMarkdown = mkLang(WikiMarkdown) - - -let startState = EditorState.create({ - doc: defaultMd, - extensions: [ - highlightSpecialChars(), - history(), - drawSelection(), - dropCursor(), - // EditorState.allowMultipleSelections.of(true), - indentOnInput(), - // defaultHighlightStyle.fallback, - mdStyle, - bracketMatching(), - closeBrackets(), - autocompletion(), - lineWrapper([ - {selector: "ATXHeading1", class: "line-h1"}, - {selector: "ATXHeading2", class: "line-h2"}, - {selector: "ListItem", class: "line-li"}, - {selector: "Blockquote", class: "line-blockquote"}, - {selector: "CodeBlock", class: "line-code"}, - {selector: "FencedCode", class: "line-fenced-code"}, - ]), - rectangularSelection(), - keymap.of([ - ...closeBracketsKeymap, - ...standardKeymap, - ...searchKeymap, - ...historyKeymap, - ...foldKeymap, - ...completionKeymap, - ...lintKeymap, - indentWithTab, - { - key: "Ctrl-b", - mac: "Cmd-b", - run: insertMarker('**') - }, - { - key: "Ctrl-i", - mac: "Cmd-i", - run: insertMarker('_') - } - ]), - EditorView.domEventHandlers({ - click: (event: MouseEvent, view: EditorView) => { - if (event.metaKey || event.ctrlKey) { - console.log("Navigate click"); - let coords = view.posAtCoords(event); - console.log("Coords", view.state.doc.sliceString(coords, coords + 1)); - return false; - } - } - }), - markdown({ - base: myMarkdown, - }), - EditorView.lineWrapping - ] -}) - -let view = new EditorView({ - state: startState, - parent: document.getElementById('editor') -}); - -view.focus(); diff --git a/src/styles.css b/src/styles.css deleted file mode 100644 index 55ffcea..0000000 --- a/src/styles.css +++ /dev/null @@ -1,111 +0,0 @@ -#editor { - width: 100%; - height: 100%; - position: absolute; - left: 0; - top: 0; -} - -:root { - --ident: 18px; -} - -.cm-editor { - width: 100%; - height: 100%; - font-size: var(--ident); -} - -.cm-editor .cm-content { - font-family: "Menlo"; - margin: 25px; -} - -.cm-editor .cm-selectionBackground { - background-color: #d7e1f6 !important; -} - -.cm-editor .h1 { - font-size: 1.5em; - color: #fff; - font-weight: bold; -} - -.cm-editor .cm-line.line-h1 { - display: block; - background-color: rgba(0, 15, 52, 0.6); -} - -.cm-editor .h1.meta { - color: orange; -} - -.cm-editor .h2 { - font-size: 1.2em; - color: #fff; - font-weight: bold; -} - -.cm-editor .cm-line.line-h2 { - display: block; - background-color: rgba(0, 15, 52, 0.6); -} - -.cm-editor .h2.meta { - color: orange; -} - -.cm-editor .line-code { - background-color: #efefef; - margin-left: 30px; -} - -.cm-editor .line-fenced-code { - background-color: #efefef; -} - -.cm-editor .meta { - color: #520130; -} - -.cm-editor .line-blockquote { - background-color: #eee; - color: #676767; - text-indent: calc(-1 * (var(--ident) + 3px)); - padding-left: var(--ident); -} - -.cm-editor .emphasis { - font-style: italic; -} - -.cm-editor .strong { - font-weight: 900; -} - -.cm-editor .link:not(.meta,.url) { - color: #0330cb; - text-decoration: underline; -} - -.cm-editor .link.url { - color: #7e7d7d; -} - -.cm-editor .wiki-link { - color: #0330cb; - /*text-decoration: underline;*/ -} - -.cm-editor .mention { - color: gray; -} - -.cm-editor .tag { - color: #8d8d8d; -} - -.cm-editor .line-li { - text-indent: calc(-1 * var(--ident) - 3px); - margin-left: var(--ident); -} diff --git a/webapp/.DS_Store b/webapp/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a090ae5e90f3e0c265d7ecc483fb8e64bfec38c8 GIT binary patch literal 6148 zcmeHK%}T>S5Z-O8Nhm@O3Oz1(Em+%H5icRu7cim+m718M!I&*cYYwH5v%Zi|;`2DO zy8(+mi`W_1{pNQ!`$6`HF~+@lbjVnXF=j(UbgvE7Ofn+JG4g4c$PlcLaB5#Nm%JYcok2I zaclQXrn4YUCz&dUqY0$kUdL%93s26|C|9+<4mghOj9cx+VsPB+i2l)V*%6DAUbiC# z{o!)y*n9g2rx)Yrtv!8<5sHLre_CNg~lPnBI|5fTH$05L!eY&HYt zT(Fy)O#`i-7$64LFo64mfQINAEH$dF13J7uW4wWg0y@4W5QRb4V5t!zAY7LM>QZi= z7+jZwUzj}CV5w1;Gp=Taam>usPi2-6@m4Ui8TX_DT!!NV;k-u6( z7BN5!{4)l4W8{xKSd=+ie=HBrS^@1I8Vcr>sDOaJatQzf_mQ>=>bO81@?3+ZMjQqG RsvM9m0*Vmoh=E^V;0thtNr(Ud literal 0 HcmV?d00001 diff --git a/webapp/.parcelrc b/webapp/.parcelrc new file mode 100644 index 0000000..c6b287a --- /dev/null +++ b/webapp/.parcelrc @@ -0,0 +1,6 @@ +{ + "extends": "@parcel/config-default", + "validators": { + "*.{ts,tsx}": ["@parcel/validator-typescript"] + } +} \ No newline at end of file diff --git a/package.json b/webapp/package.json similarity index 63% rename from package.json rename to webapp/package.json index c2da98f..9983f1a 100644 --- a/package.json +++ b/webapp/package.json @@ -9,13 +9,19 @@ "build": "parcel build" }, "devDependencies": { - "parcel": "^2.3.1" + "@parcel/validator-typescript": "^2.3.2", + "@types/react": "^17.0.39", + "@types/react-dom": "^17.0.11", + "parcel": "^2.3.2", + "typescript": ">=3.0.0" }, "dependencies": { "@codemirror/basic-setup": "^0.19.1", "@codemirror/commands": "^0.19.8", "@codemirror/lang-markdown": "^0.19.6", "@codemirror/state": "^0.19.7", - "@codemirror/view": "^0.19.42" + "@codemirror/view": "^0.19.42", + "react": "^17.0.2", + "react-dom": "^17.0.2" } } diff --git a/webapp/src/.DS_Store b/webapp/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 { + Promise.resolve() + .then(async () => { + console.log("Saving"); + await this.save(); + }) + .catch((e) => console.error(e)); + return true; + }, + }, + ]), + EditorView.domEventHandlers({ + click: (event, view) => { + if (event.metaKey || event.ctrlKey) { + console.log("Navigate click"); + let coords = view.posAtCoords(event); + console.log("Coords", view.state.doc.sliceString(coords, coords + 1)); + return false; + } + }, + }), + markdown({ + base: customMarkDown, + }), + StateField.define({ + create: () => null, + update: (value, transaction) => { + if (transaction.docChanged) { + console.log("Something changed"); + } + return null; + }, + }), + ], + }); + } +} +export const App = () => { + const editorRef = useRef(); + useEffect(() => { + let editor = new Editor(editorRef.current, "", ""); + editor.focus(); + // @ts-ignore + window.editor = editor; + fs.readNote("start").then((text) => { + editor.load("start", text); + }); + }, []); + return (_jsxs(_Fragment, { children: [_jsx("div", { id: "top", children: "Hello" }, void 0), _jsx("div", { id: "editor", ref: editorRef }, void 0), _jsx("div", { id: "bottom", children: "Bottom" }, void 0)] }, void 0)); +}; +ReactDOM.render(_jsx(App, {}, void 0), document.body); diff --git a/webapp/src/app.tsx b/webapp/src/app.tsx new file mode 100644 index 0000000..c204969 --- /dev/null +++ b/webapp/src/app.tsx @@ -0,0 +1,173 @@ +import { autocompletion, completionKeymap } from "@codemirror/autocomplete"; +import { closeBrackets, closeBracketsKeymap } from "@codemirror/closebrackets"; +import { indentWithTab, standardKeymap } from "@codemirror/commands"; +import { history, historyKeymap } from "@codemirror/history"; +import { indentOnInput } from "@codemirror/language"; +import { bracketMatching } from "@codemirror/matchbrackets"; +import { searchKeymap } from "@codemirror/search"; +import { EditorState, StateField } from "@codemirror/state"; + +import { + drawSelection, + dropCursor, + EditorView, + highlightSpecialChars, + keymap, +} from "@codemirror/view"; +import * as commands from "./commands"; +import { markdown } from "./markdown"; +import { lineWrapper } from "./lineWrapper"; +import customMarkDown from "./parser"; +import customMarkdownStyle from "./style"; +import { HttpFileSystem } from "./fs"; + +import ReactDOM from "react-dom"; +import { MutableRefObject, useEffect, useRef, useState } from "react"; + +const fs = new HttpFileSystem("http://localhost:2222/fs"); + +type AppState = { + currentNote: string; +}; + +class Editor { + view: EditorView; + currentNote: string; + + constructor(parent: Element, currentNote: string, text: string) { + this.view = new EditorView({ + state: this.createEditorState(text), + parent: parent, + }); + this.currentNote = currentNote; + } + + load(name: string, text: string) { + this.currentNote = name; + this.view.setState(this.createEditorState(text)); + } + + async save() { + await fs.writeNote(this.currentNote, this.view.state.sliceDoc()); + } + + focus() { + this.view.focus(); + } + + private createEditorState(text: string): EditorState { + return EditorState.create({ + doc: text, + extensions: [ + highlightSpecialChars(), + history(), + drawSelection(), + dropCursor(), + indentOnInput(), + customMarkdownStyle, + bracketMatching(), + closeBrackets(), + autocompletion(), + EditorView.lineWrapping, + lineWrapper([ + { selector: "ATXHeading1", class: "line-h1" }, + { selector: "ATXHeading2", class: "line-h2" }, + { selector: "ListItem", class: "line-li" }, + { selector: "Blockquote", class: "line-blockquote" }, + { selector: "CodeBlock", class: "line-code" }, + { selector: "FencedCode", class: "line-fenced-code" }, + ]), + keymap.of([ + ...closeBracketsKeymap, + ...standardKeymap, + ...searchKeymap, + ...historyKeymap, + ...completionKeymap, + indentWithTab, + { + key: "Ctrl-b", + mac: "Cmd-b", + run: commands.insertMarker("**"), + }, + { + key: "Ctrl-i", + mac: "Cmd-i", + run: commands.insertMarker("_"), + }, + { + key: "Ctrl-s", + mac: "Cmd-s", + run: (target: EditorView): boolean => { + Promise.resolve() + .then(async () => { + console.log("Saving"); + await this.save(); + }) + .catch((e) => console.error(e)); + return true; + }, + }, + ]), + EditorView.domEventHandlers({ + click: (event: MouseEvent, view: EditorView) => { + if (event.metaKey || event.ctrlKey) { + console.log("Navigate click"); + let coords = view.posAtCoords(event); + console.log( + "Coords", + view.state.doc.sliceString(coords!, coords! + 1) + ); + return false; + } + }, + }), + markdown({ + base: customMarkDown, + }), + StateField.define({ + create: () => null, + update: (value, transaction) => { + if (transaction.docChanged) { + console.log("Something changed"); + } + return null; + }, + }), + ], + }); + } +} + +function TopBar({ editor }: { editor: Editor | null }) { + return ( +
+ This is the top bar, do something cool: {editor?.currentNote} +
+ ); +} + +function App() { + const editorRef = useRef(null); + const [editor, setEditor] = useState(null); + + useEffect(() => { + let editor = new Editor(editorRef.current!, "", ""); + editor.focus(); + // @ts-ignore + window.editor = editor; + fs.readNote("start").then((text) => { + editor.load("start", text); + }); + setEditor(editor); + }, []); + + return ( + <> + +
+
Bottom
+ + ); +} + +ReactDOM.render(, document.body); diff --git a/webapp/src/commands.js b/webapp/src/commands.js new file mode 100644 index 0000000..178c7dc --- /dev/null +++ b/webapp/src/commands.js @@ -0,0 +1,38 @@ +import { EditorSelection, Transaction } from "@codemirror/state"; +import { Text } from "@codemirror/text"; +export function insertMarker(marker) { + return ({ state, dispatch }) => { + const changes = state.changeByRange((range) => { + const isBoldBefore = state.sliceDoc(range.from - marker.length, range.from) === marker; + const isBoldAfter = state.sliceDoc(range.to, range.to + marker.length) === marker; + const changes = []; + changes.push(isBoldBefore ? { + from: range.from - marker.length, + to: range.from, + insert: Text.of(['']) + } : { + from: range.from, + insert: Text.of([marker]), + }); + changes.push(isBoldAfter ? { + from: range.to, + to: range.to + marker.length, + insert: Text.of(['']) + } : { + from: range.to, + insert: Text.of([marker]), + }); + const extendBefore = isBoldBefore ? -marker.length : marker.length; + const extendAfter = isBoldAfter ? -marker.length : marker.length; + return { + changes, + range: EditorSelection.range(range.from + extendBefore, range.to + extendAfter), + }; + }); + dispatch(state.update(changes, { + scrollIntoView: true, + annotations: Transaction.userEvent.of('input'), + })); + return true; + }; +} diff --git a/webapp/src/commands.ts b/webapp/src/commands.ts new file mode 100644 index 0000000..c5af4d8 --- /dev/null +++ b/webapp/src/commands.ts @@ -0,0 +1,47 @@ +import { EditorSelection, EditorState, StateCommand, Transaction } from "@codemirror/state"; +import { Text } from "@codemirror/text"; + +export function insertMarker(marker: string): StateCommand { + return ({ state, dispatch }) => { + const changes = state.changeByRange((range) => { + const isBoldBefore = state.sliceDoc(range.from - marker.length, range.from) === marker; + const isBoldAfter = state.sliceDoc(range.to, range.to + marker.length) === marker; + const changes = []; + + changes.push(isBoldBefore ? { + from: range.from - marker.length, + to: range.from, + insert: Text.of(['']) + } : { + from: range.from, + insert: Text.of([marker]), + }) + + changes.push(isBoldAfter ? { + from: range.to, + to: range.to + marker.length, + insert: Text.of(['']) + } : { + from: range.to, + insert: Text.of([marker]), + }) + + const extendBefore = isBoldBefore ? -marker.length : marker.length; + const extendAfter = isBoldAfter ? -marker.length : marker.length; + + return { + changes, + range: EditorSelection.range(range.from + extendBefore, range.to + extendAfter), + } + }) + + dispatch( + state.update(changes, { + scrollIntoView: true, + annotations: Transaction.userEvent.of('input'), + }) + ) + + return true + }; +} \ No newline at end of file diff --git a/webapp/src/customtags.js b/webapp/src/customtags.js new file mode 100644 index 0000000..c5d9164 --- /dev/null +++ b/webapp/src/customtags.js @@ -0,0 +1,4 @@ +import { Tag } from '@codemirror/highlight'; +export const WikiLinkTag = Tag.define(); +export const TagTag = Tag.define(); +export const MentionTag = Tag.define(); diff --git a/webapp/src/customtags.ts b/webapp/src/customtags.ts new file mode 100644 index 0000000..2ea41d6 --- /dev/null +++ b/webapp/src/customtags.ts @@ -0,0 +1,5 @@ +import { Tag } from '@codemirror/highlight'; + +export const WikiLinkTag = Tag.define(); +export const TagTag = Tag.define(); +export const MentionTag = Tag.define(); diff --git a/webapp/src/fs.js b/webapp/src/fs.js new file mode 100644 index 0000000..a32539d --- /dev/null +++ b/webapp/src/fs.js @@ -0,0 +1,24 @@ +export class HttpFileSystem { + constructor(url) { + this.url = url; + } + async listNotes() { + let req = await fetch(this.url, { + method: 'GET' + }); + return (await req.json()).map((name) => ({ name })); + } + async readNote(name) { + let req = await fetch(`${this.url}/${name}`, { + method: 'GET' + }); + return await req.text(); + } + async writeNote(name, text) { + let req = await fetch(`${this.url}/${name}`, { + method: 'PUT', + body: text + }); + await req.text(); + } +} diff --git a/webapp/src/fs.ts b/webapp/src/fs.ts new file mode 100644 index 0000000..05459f2 --- /dev/null +++ b/webapp/src/fs.ts @@ -0,0 +1,38 @@ + +export interface NoteMeta { + name: string; +} + +export interface FileSystem { + listNotes(): Promise; + readNote(name: string): Promise; + writeNote(name: string, text: string): Promise; +} + +export class HttpFileSystem implements FileSystem { + url: string; + + constructor(url: string) { + this.url = url; + } + async listNotes(): Promise { + let req = await fetch(this.url, { + method: 'GET' + }); + + return (await req.json()).map((name: string) => ({ name })); + } + async readNote(name: string): Promise { + let req = await fetch(`${this.url}/${name}`, { + method: 'GET' + }); + return await req.text(); + } + async writeNote(name: string, text: string): Promise { + let req = await fetch(`${this.url}/${name}`, { + method: 'PUT', + body: text + }); + await req.text(); + } +} \ No newline at end of file diff --git a/src/index.html b/webapp/src/index.html similarity index 72% rename from src/index.html rename to webapp/src/index.html index 2d5e16b..733d73c 100644 --- a/src/index.html +++ b/webapp/src/index.html @@ -4,11 +4,9 @@ Noot - + - -
- + diff --git a/webapp/src/lineWrapper.js b/webapp/src/lineWrapper.js new file mode 100644 index 0000000..71b5d9f --- /dev/null +++ b/webapp/src/lineWrapper.js @@ -0,0 +1,45 @@ +import { syntaxTree } from '@codemirror/language'; +import { Decoration, ViewPlugin } from '@codemirror/view'; +function wrapLines(view, wrapElements) { + let widgets = []; + for (let { from, to } of view.visibleRanges) { + const doc = view.state.doc; + syntaxTree(view.state).iterate({ + from, to, + enter: (type, from, to) => { + const bodyText = doc.sliceString(from, to); + // console.log("Enter", type.name, bodyText); + for (let wrapElement of wrapElements) { + if (type.name == wrapElement.selector) { + const bodyText = doc.sliceString(from, to); + // console.log("Found", type.name, "with: ", bodyText); + let idx = from; + for (let line of bodyText.split("\n")) { + widgets.push(Decoration.line({ + class: wrapElement.class, + }).range(doc.lineAt(idx).from)); + idx += line.length + 1; + } + } + } + }, + leave(type, from, to) { + // console.log("Leaving", type.name); + } + }); + } + // console.log("All widgets", widgets); + return Decoration.set(widgets); +} +export const lineWrapper = (wrapElements) => ViewPlugin.fromClass(class { + constructor(view) { + this.decorations = wrapLines(view, wrapElements); + } + update(update) { + if (update.docChanged || update.viewportChanged) { + this.decorations = wrapLines(update.view, wrapElements); + } + } +}, { + decorations: v => v.decorations, +}); diff --git a/webapp/src/lineWrapper.ts b/webapp/src/lineWrapper.ts new file mode 100644 index 0000000..56b3bc0 --- /dev/null +++ b/webapp/src/lineWrapper.ts @@ -0,0 +1,56 @@ +import { syntaxTree } from '@codemirror/language'; +import { + Decoration, + DecorationSet, EditorView, ViewPlugin, + ViewUpdate +} from '@codemirror/view'; + +import { Range } from '@codemirror/rangeset'; + +interface WrapElement { + selector: string; + class: string; +} +function wrapLines(view: EditorView, wrapElements: WrapElement[]) { + let widgets: Range[] = []; + for (let { from, to } of view.visibleRanges) { + const doc = view.state.doc; + syntaxTree(view.state).iterate({ + from, to, + enter: (type, from, to) => { + const bodyText = doc.sliceString(from, to); + for (let wrapElement of wrapElements) { + if (type.name == wrapElement.selector) { + const bodyText = doc.sliceString(from, to); + let idx = from; + for (let line of bodyText.split("\n")) { + widgets.push(Decoration.line({ + class: wrapElement.class, + }).range(doc.lineAt(idx).from)); + idx += line.length + 1; + } + } + } + }, + leave(type, from: number, to: number) { + } + }); + } + // console.log("All widgets", widgets); + return Decoration.set(widgets); +} +export const lineWrapper = (wrapElements: WrapElement[]) => ViewPlugin.fromClass(class { + decorations: DecorationSet; + + constructor(view: EditorView) { + this.decorations = wrapLines(view, wrapElements); + } + + update(update: ViewUpdate) { + if (update.docChanged || update.viewportChanged) { + this.decorations = wrapLines(update.view, wrapElements); + } + } +}, { + decorations: v => v.decorations, +}); diff --git a/webapp/src/markdown/commands.js b/webapp/src/markdown/commands.js new file mode 100644 index 0000000..844b182 --- /dev/null +++ b/webapp/src/markdown/commands.js @@ -0,0 +1,234 @@ +import { EditorSelection } from "@codemirror/state"; +import { syntaxTree } from "@codemirror/language"; +import { markdownLanguage } from "./markdown"; +function nodeStart(node, doc) { + return doc.sliceString(node.from, node.from + 50); +} +class Context { + constructor(node, from, to, spaceBefore, spaceAfter, type, item) { + this.node = node; + this.from = from; + this.to = to; + this.spaceBefore = spaceBefore; + this.spaceAfter = spaceAfter; + this.type = type; + this.item = item; + } + blank(trailing = true) { + let result = this.spaceBefore; + if (this.node.name == "Blockquote") + result += ">"; + else + for (let i = this.to - this.from - result.length - this.spaceAfter.length; i > 0; i--) + result += " "; + return result + (trailing ? this.spaceAfter : ""); + } + marker(doc, add) { + let number = this.node.name == "OrderedList" ? String((+itemNumber(this.item, doc)[2] + add)) : ""; + return this.spaceBefore + number + this.type + this.spaceAfter; + } +} +function getContext(node, line, doc) { + let nodes = []; + for (let cur = node; cur && cur.name != "Document"; cur = cur.parent) { + if (cur.name == "ListItem" || cur.name == "Blockquote") + nodes.push(cur); + } + let context = [], pos = 0; + for (let i = nodes.length - 1; i >= 0; i--) { + let node = nodes[i], match, start = pos; + if (node.name == "Blockquote" && (match = /^[ \t]*>( ?)/.exec(line.slice(pos)))) { + pos += match[0].length; + context.push(new Context(node, start, pos, "", match[1], ">", null)); + } + else if (node.name == "ListItem" && node.parent.name == "OrderedList" && + (match = /^([ \t]*)\d+([.)])([ \t]*)/.exec(nodeStart(node, doc)))) { + let after = match[3], len = match[0].length; + if (after.length >= 4) { + after = after.slice(0, after.length - 4); + len -= 4; + } + pos += len; + context.push(new Context(node.parent, start, pos, match[1], after, match[2], node)); + } + else if (node.name == "ListItem" && node.parent.name == "BulletList" && + (match = /^([ \t]*)([-+*])([ \t]+)/.exec(nodeStart(node, doc)))) { + let after = match[3], len = match[0].length; + if (after.length > 4) { + after = after.slice(0, after.length - 4); + len -= 4; + } + pos += len; + context.push(new Context(node.parent, start, pos, match[1], after, match[2], node)); + } + } + return context; +} +function itemNumber(item, doc) { + return /^(\s*)(\d+)(?=[.)])/.exec(doc.sliceString(item.from, item.from + 10)); +} +function renumberList(after, doc, changes, offset = 0) { + for (let prev = -1, node = after;;) { + if (node.name == "ListItem") { + let m = itemNumber(node, doc); + let number = +m[2]; + if (prev >= 0) { + if (number != prev + 1) + return; + changes.push({ from: node.from + m[1].length, to: node.from + m[0].length, insert: String(prev + 2 + offset) }); + } + prev = number; + } + let next = node.nextSibling; + if (!next) + break; + node = next; + } +} +/// This command, when invoked in Markdown context with cursor +/// selection(s), will create a new line with the markup for +/// blockquotes and lists that were active on the old line. If the +/// cursor was directly after the end of the markup for the old line, +/// trailing whitespace and list markers are removed from that line. +/// +/// The command does nothing in non-Markdown context, so it should +/// not be used as the only binding for Enter (even in a Markdown +/// document, HTML and code regions might use a different language). +export const insertNewlineContinueMarkup = ({ state, dispatch }) => { + let tree = syntaxTree(state), { doc } = state; + let dont = null, changes = state.changeByRange(range => { + if (!range.empty || !markdownLanguage.isActiveAt(state, range.from)) + return dont = { range }; + let pos = range.from, line = doc.lineAt(pos); + let context = getContext(tree.resolveInner(pos, -1), line.text, doc); + while (context.length && context[context.length - 1].from > pos - line.from) + context.pop(); + if (!context.length) + return dont = { range }; + let inner = context[context.length - 1]; + if (inner.to - inner.spaceAfter.length > pos - line.from) + return dont = { range }; + let emptyLine = pos >= (inner.to - inner.spaceAfter.length) && !/\S/.test(line.text.slice(inner.to)); + // Empty line in list + if (inner.item && emptyLine) { + // First list item or blank line before: delete a level of markup + if (inner.node.firstChild.to >= pos || + line.from > 0 && !/[^\s>]/.test(doc.lineAt(line.from - 1).text)) { + let next = context.length > 1 ? context[context.length - 2] : null; + let delTo, insert = ""; + if (next && next.item) { // Re-add marker for the list at the next level + delTo = line.from + next.from; + insert = next.marker(doc, 1); + } + else { + delTo = line.from + (next ? next.to : 0); + } + let changes = [{ from: delTo, to: pos, insert }]; + if (inner.node.name == "OrderedList") + renumberList(inner.item, doc, changes, -2); + if (next && next.node.name == "OrderedList") + renumberList(next.item, doc, changes); + return { range: EditorSelection.cursor(delTo + insert.length), changes }; + } + else { // Move this line down + let insert = ""; + for (let i = 0, e = context.length - 2; i <= e; i++) + insert += context[i].blank(i < e); + insert += state.lineBreak; + return { range: EditorSelection.cursor(pos + insert.length), changes: { from: line.from, insert } }; + } + } + if (inner.node.name == "Blockquote" && emptyLine && line.from) { + let prevLine = doc.lineAt(line.from - 1), quoted = />\s*$/.exec(prevLine.text); + // Two aligned empty quoted lines in a row + if (quoted && quoted.index == inner.from) { + let changes = state.changes([{ from: prevLine.from + quoted.index, to: prevLine.to }, + { from: line.from + inner.from, to: line.to }]); + return { range: range.map(changes), changes }; + } + } + let changes = []; + if (inner.node.name == "OrderedList") + renumberList(inner.item, doc, changes); + let insert = state.lineBreak; + let continued = inner.item && inner.item.from < line.from; + // If not dedented + if (!continued || /^[\s\d.)\-+*>]*/.exec(line.text)[0].length >= inner.to) { + for (let i = 0, e = context.length - 1; i <= e; i++) + insert += i == e && !continued ? context[i].marker(doc, 1) : context[i].blank(); + } + let from = pos; + while (from > line.from && /\s/.test(line.text.charAt(from - line.from - 1))) + from--; + changes.push({ from, to: pos, insert }); + return { range: EditorSelection.cursor(from + insert.length), changes }; + }); + if (dont) + return false; + dispatch(state.update(changes, { scrollIntoView: true, userEvent: "input" })); + return true; +}; +function isMark(node) { + return node.name == "QuoteMark" || node.name == "ListMark"; +} +function contextNodeForDelete(tree, pos) { + let node = tree.resolveInner(pos, -1), scan = pos; + if (isMark(node)) { + scan = node.from; + node = node.parent; + } + for (let prev; prev = node.childBefore(scan);) { + if (isMark(prev)) { + scan = prev.from; + } + else if (prev.name == "OrderedList" || prev.name == "BulletList") { + node = prev.lastChild; + scan = node.to; + } + else { + break; + } + } + return node; +} +/// This command will, when invoked in a Markdown context with the +/// cursor directly after list or blockquote markup, delete one level +/// of markup. When the markup is for a list, it will be replaced by +/// spaces on the first invocation (a further invocation will delete +/// the spaces), to make it easy to continue a list. +/// +/// When not after Markdown block markup, this command will return +/// false, so it is intended to be bound alongside other deletion +/// commands, with a higher precedence than the more generic commands. +export const deleteMarkupBackward = ({ state, dispatch }) => { + let tree = syntaxTree(state); + let dont = null, changes = state.changeByRange(range => { + let pos = range.from, { doc } = state; + if (range.empty && markdownLanguage.isActiveAt(state, range.from)) { + let line = doc.lineAt(pos); + let context = getContext(contextNodeForDelete(tree, pos), line.text, doc); + if (context.length) { + let inner = context[context.length - 1]; + let spaceEnd = inner.to - inner.spaceAfter.length + (inner.spaceAfter ? 1 : 0); + // Delete extra trailing space after markup + if (pos - line.from > spaceEnd && !/\S/.test(line.text.slice(spaceEnd, pos - line.from))) + return { range: EditorSelection.cursor(line.from + spaceEnd), + changes: { from: line.from + spaceEnd, to: pos } }; + if (pos - line.from == spaceEnd) { + let start = line.from + inner.from; + // Replace a list item marker with blank space + if (inner.item && inner.node.from < inner.item.from && /\S/.test(line.text.slice(inner.from, inner.to))) + return { range, changes: { from: start, to: line.from + inner.to, insert: inner.blank() } }; + // Delete one level of indentation + if (start < pos) + return { range: EditorSelection.cursor(start), changes: { from: start, to: pos } }; + } + } + } + return dont = { range }; + }); + if (dont) + return false; + dispatch(state.update(changes, { scrollIntoView: true, userEvent: "delete" })); + return true; +}; diff --git a/src/markdown/commands.ts b/webapp/src/markdown/commands.ts similarity index 100% rename from src/markdown/commands.ts rename to webapp/src/markdown/commands.ts diff --git a/webapp/src/markdown/index.js b/webapp/src/markdown/index.js new file mode 100644 index 0000000..6b63484 --- /dev/null +++ b/webapp/src/markdown/index.js @@ -0,0 +1,37 @@ +import { Prec } from "@codemirror/state"; +import { keymap } from "@codemirror/view"; +import { LanguageSupport } from "@codemirror/language"; +import { MarkdownParser, parseCode } from "@lezer/markdown"; +import { html } from "@codemirror/lang-html"; +import { commonmarkLanguage, markdownLanguage, mkLang, getCodeParser } from "./markdown"; +import { insertNewlineContinueMarkup, deleteMarkupBackward } from "./commands"; +export { commonmarkLanguage, markdownLanguage, insertNewlineContinueMarkup, deleteMarkupBackward }; +/// A small keymap with Markdown-specific bindings. Binds Enter to +/// [`insertNewlineContinueMarkup`](#lang-markdown.insertNewlineContinueMarkup) +/// and Backspace to +/// [`deleteMarkupBackward`](#lang-markdown.deleteMarkupBackward). +export const markdownKeymap = [ + { key: "Enter", run: insertNewlineContinueMarkup }, + { key: "Backspace", run: deleteMarkupBackward } +]; +const htmlNoMatch = html({ matchClosingTags: false }); +/// Markdown language support. +export function markdown(config = {}) { + let { codeLanguages, defaultCodeLanguage, addKeymap = true, base: { parser } = commonmarkLanguage } = config; + if (!(parser instanceof MarkdownParser)) + throw new RangeError("Base parser provided to `markdown` should be a Markdown parser"); + let extensions = config.extensions ? [config.extensions] : []; + let support = [htmlNoMatch.support], defaultCode; + if (defaultCodeLanguage instanceof LanguageSupport) { + support.push(defaultCodeLanguage.support); + defaultCode = defaultCodeLanguage.language; + } + else if (defaultCodeLanguage) { + defaultCode = defaultCodeLanguage; + } + let codeParser = codeLanguages || defaultCode ? getCodeParser(codeLanguages || [], defaultCode) : undefined; + extensions.push(parseCode({ codeParser, htmlParser: htmlNoMatch.language.parser })); + if (addKeymap) + support.push(Prec.high(keymap.of(markdownKeymap))); + return new LanguageSupport(mkLang(parser.configure(extensions)), support); +} diff --git a/src/markdown/index.ts b/webapp/src/markdown/index.ts similarity index 100% rename from src/markdown/index.ts rename to webapp/src/markdown/index.ts diff --git a/webapp/src/markdown/markdown.js b/webapp/src/markdown/markdown.js new file mode 100644 index 0000000..6c7b4bd --- /dev/null +++ b/webapp/src/markdown/markdown.js @@ -0,0 +1,75 @@ +import { Language, defineLanguageFacet, languageDataProp, foldNodeProp, indentNodeProp, LanguageDescription, ParseContext } from "@codemirror/language"; +import { styleTags, tags as t } from "@codemirror/highlight"; +import { parser as baseParser, GFM, Subscript, Superscript, Emoji } from "@lezer/markdown"; +const data = defineLanguageFacet({ block: { open: "" } }); +export const commonmark = baseParser.configure({ + props: [ + styleTags({ + "Blockquote/...": t.quote, + HorizontalRule: t.contentSeparator, + "ATXHeading1/... SetextHeading1/...": t.heading1, + "ATXHeading2/... SetextHeading2/...": t.heading2, + "ATXHeading3/...": t.heading3, + "ATXHeading4/...": t.heading4, + "ATXHeading5/...": t.heading5, + "ATXHeading6/...": t.heading6, + "Comment CommentBlock": t.comment, + Escape: t.escape, + Entity: t.character, + "Emphasis/...": t.emphasis, + "StrongEmphasis/...": t.strong, + "Link/... Image/...": t.link, + "OrderedList/... BulletList/...": t.list, + // "CodeBlock/... FencedCode/...": t.blockComment, + "InlineCode CodeText": t.monospace, + URL: t.url, + "HeaderMark HardBreak QuoteMark ListMark LinkMark EmphasisMark CodeMark": t.processingInstruction, + "CodeInfo LinkLabel": t.labelName, + LinkTitle: t.string, + Paragraph: t.content + }), + foldNodeProp.add(type => { + if (!type.is("Block") || type.is("Document")) + return undefined; + return (tree, state) => ({ from: state.doc.lineAt(tree.from).to, to: tree.to }); + }), + indentNodeProp.add({ + Document: () => null + }), + languageDataProp.add({ + Document: data + }) + ] +}); +export function mkLang(parser) { + return new Language(data, parser, parser.nodeSet.types.find(t => t.name == "Document")); +} +/// Language support for strict CommonMark. +export const commonmarkLanguage = mkLang(commonmark); +const extended = commonmark.configure([GFM, Subscript, Superscript, Emoji, { + props: [ + styleTags({ + "TableDelimiter SubscriptMark SuperscriptMark StrikethroughMark": t.processingInstruction, + "TableHeader/...": t.heading, + "Strikethrough/...": t.strikethrough, + TaskMarker: t.atom, + Task: t.list, + Emoji: t.character, + "Subscript Superscript": t.special(t.content), + TableCell: t.content + }) + ] + }]); +/// Language support for [GFM](https://github.github.com/gfm/) plus +/// subscript, superscript, and emoji syntax. +export const markdownLanguage = mkLang(extended); +export function getCodeParser(languages, defaultLanguage) { + return (info) => { + let found = info && LanguageDescription.matchLanguageName(languages, info, true); + if (!found) + return defaultLanguage ? defaultLanguage.parser : null; + if (found.support) + return found.support.language.parser; + return ParseContext.getSkippingParser(found.load()); + }; +} diff --git a/src/markdown/markdown.ts b/webapp/src/markdown/markdown.ts similarity index 100% rename from src/markdown/markdown.ts rename to webapp/src/markdown/markdown.ts diff --git a/webapp/src/parser.js b/webapp/src/parser.js new file mode 100644 index 0000000..1297881 --- /dev/null +++ b/webapp/src/parser.js @@ -0,0 +1,57 @@ +import { styleTags } from '@codemirror/highlight'; +import { commonmark, mkLang } from "./markdown/markdown"; +import * as ct from './customtags'; +const WikiLink = { + defineNodes: ["WikiLink"], + parseInline: [{ + name: "WikiLink", + parse(cx, next, pos) { + let match; + if (next != 91 /* '[' */ || !(match = /^\[[^\]]+\]\]/.exec(cx.slice(pos + 1, cx.end)))) { + return -1; + } + return cx.addElement(cx.elt("WikiLink", pos, pos + 1 + match[0].length)); + }, + after: "Emphasis" + }] +}; +const AtMention = { + defineNodes: ["AtMention"], + parseInline: [{ + name: "AtMention", + parse(cx, next, pos) { + let match; + if (next != 64 /* '@' */ || !(match = /^[A-Za-z\.]+/.exec(cx.slice(pos + 1, cx.end)))) { + return -1; + } + return cx.addElement(cx.elt("AtMention", pos, pos + 1 + match[0].length)); + }, + after: "Emphasis" + }] +}; +const TagLink = { + defineNodes: ["TagLink"], + parseInline: [{ + name: "TagLink", + parse(cx, next, pos) { + let match; + if (next != 35 /* '#' */ || !(match = /^[A-Za-z\.]+/.exec(cx.slice(pos + 1, cx.end)))) { + return -1; + } + return cx.addElement(cx.elt("TagLink", pos, pos + 1 + match[0].length)); + }, + after: "Emphasis" + }] +}; +const WikiMarkdown = commonmark.configure([WikiLink, AtMention, TagLink, { + props: [ + styleTags({ + WikiLink: ct.WikiLinkTag, + AtMention: ct.MentionTag, + TagLink: ct.TagTag, + }) + ] + }]); +/// Language support for [GFM](https://github.github.com/gfm/) plus +/// subscript, superscript, and emoji syntax. +export default mkLang(WikiMarkdown); diff --git a/webapp/src/parser.ts b/webapp/src/parser.ts new file mode 100644 index 0000000..e56f4e7 --- /dev/null +++ b/webapp/src/parser.ts @@ -0,0 +1,60 @@ +import { styleTags } from '@codemirror/highlight'; +import { MarkdownConfig } from "@lezer/markdown"; +import { commonmark, mkLang } from "./markdown/markdown"; +import * as ct from './customtags'; + +const WikiLink: MarkdownConfig = { + defineNodes: ["WikiLink"], + parseInline: [{ + name: "WikiLink", + parse(cx, next, pos) { + let match: RegExpMatchArray | null; + if (next != 91 /* '[' */ || !(match = /^\[[^\]]+\]\]/.exec(cx.slice(pos + 1, cx.end)))) { + return -1; + } + return cx.addElement(cx.elt("WikiLink", pos, pos + 1 + match[0].length)); + }, + after: "Emphasis" + }] +}; +const AtMention: MarkdownConfig = { + defineNodes: ["AtMention"], + parseInline: [{ + name: "AtMention", + parse(cx, next, pos) { + let match: RegExpMatchArray | null; + if (next != 64 /* '@' */ || !(match = /^[A-Za-z\.]+/.exec(cx.slice(pos + 1, cx.end)))) { + return -1; + } + return cx.addElement(cx.elt("AtMention", pos, pos + 1 + match[0].length)); + }, + after: "Emphasis" + }] +}; +const TagLink: MarkdownConfig = { + defineNodes: ["TagLink"], + parseInline: [{ + name: "TagLink", + parse(cx, next, pos) { + let match: RegExpMatchArray | null; + if (next != 35 /* '#' */ || !(match = /^[A-Za-z\.]+/.exec(cx.slice(pos + 1, cx.end)))) { + return -1; + } + return cx.addElement(cx.elt("TagLink", pos, pos + 1 + match[0].length)); + }, + after: "Emphasis" + }] +}; +const WikiMarkdown = commonmark.configure([WikiLink, AtMention, TagLink, { + props: [ + styleTags({ + WikiLink: ct.WikiLinkTag, + AtMention: ct.MentionTag, + TagLink: ct.TagTag, + }) + ] +}]); +/// Language support for [GFM](https://github.github.com/gfm/) plus +/// subscript, superscript, and emoji syntax. + +export default mkLang(WikiMarkdown); diff --git a/webapp/src/style.js b/webapp/src/style.js new file mode 100644 index 0000000..bb75d3b --- /dev/null +++ b/webapp/src/style.js @@ -0,0 +1,31 @@ +import { HighlightStyle, tags as t } from '@codemirror/highlight'; +import * as ct from './customtags'; +export default HighlightStyle.define([ + { tag: t.heading1, class: "h1" }, + { tag: t.heading2, class: "h2" }, + { tag: t.link, class: "link" }, + { tag: t.meta, class: "meta" }, + { tag: t.quote, class: "quote" }, + { tag: t.monospace, class: "code" }, + { tag: t.url, class: "url" }, + { tag: ct.WikiLinkTag, class: "wiki-link" }, + { tag: ct.TagTag, class: "tag" }, + { tag: ct.MentionTag, class: "mention" }, + { tag: t.emphasis, class: "emphasis" }, + { tag: t.strong, class: "strong" }, + { tag: t.atom, class: "atom" }, + { tag: t.bool, class: "bool" }, + { tag: t.url, class: "url" }, + { tag: t.inserted, class: "inserted" }, + { tag: t.deleted, class: "deleted" }, + { tag: t.literal, class: "literal" }, + { tag: t.list, class: "list" }, + { tag: t.definition, class: "li" }, + { tag: t.string, class: "string" }, + { tag: t.number, class: "number" }, + { tag: [t.regexp, t.escape, t.special(t.string)], class: "string2" }, + { tag: t.variableName, class: "variableName" }, + { tag: t.comment, class: "comment" }, + { tag: t.invalid, class: "invalid" }, + { tag: t.punctuation, class: "punctuation" } +]); diff --git a/webapp/src/style.ts b/webapp/src/style.ts new file mode 100644 index 0000000..8e8e0a5 --- /dev/null +++ b/webapp/src/style.ts @@ -0,0 +1,32 @@ +import { HighlightStyle, tags as t } from '@codemirror/highlight'; +import * as ct from './customtags'; + +export default HighlightStyle.define([ + { tag: t.heading1, class: "h1" }, + { tag: t.heading2, class: "h2" }, + { tag: t.link, class: "link" }, + { tag: t.meta, class: "meta" }, + { tag: t.quote, class: "quote" }, + { tag: t.monospace, class: "code" }, + { tag: t.url, class: "url" }, + { tag: ct.WikiLinkTag, class: "wiki-link" }, + { tag: ct.TagTag, class: "tag" }, + { tag: ct.MentionTag, class: "mention" }, + { tag: t.emphasis, class: "emphasis" }, + { tag: t.strong, class: "strong" }, + { tag: t.atom, class: "atom" }, + { tag: t.bool, class: "bool" }, + { tag: t.url, class: "url" }, + { tag: t.inserted, class: "inserted" }, + { tag: t.deleted, class: "deleted" }, + { tag: t.literal, class: "literal" }, + { tag: t.list, class: "list" }, + { tag: t.definition, class: "li" }, + { tag: t.string, class: "string" }, + { tag: t.number, class: "number" }, + { tag: [t.regexp, t.escape, t.special(t.string)], class: "string2" }, + { tag: t.variableName, class: "variableName" }, + { tag: t.comment, class: "comment" }, + { tag: t.invalid, class: "invalid" }, + { tag: t.punctuation, class: "punctuation" } +]); diff --git a/webapp/src/styles.css b/webapp/src/styles.css new file mode 100644 index 0000000..308fe3a --- /dev/null +++ b/webapp/src/styles.css @@ -0,0 +1,132 @@ +html, +body { + height: 100%; + margin: 0; + padding: 0; +} + +body { + display: flex; + flex-direction: column; +} + +#top { + height: 40px; + background-color: #eee; +} + +#bottom { + height: 40px; + background-color: #eee; + margin: 0; +} + +#editor { + flex-grow: 1; + width: 100%; + overflow-y: hidden; +} + +:root { + --ident: 18px; +} + +.cm-editor { + width: 100%; + height: 100%; + font-size: var(--ident); +} + +.cm-editor .cm-content { + font-family: "Menlo"; + margin: 25px; +} + +.cm-editor .cm-selectionBackground { + background-color: #d7e1f6 !important; +} + +.cm-editor .h1 { + font-size: 1.5em; + color: #fff; + font-weight: bold; +} + +.cm-editor .cm-line.line-h1 { + display: block; + background-color: rgba(0, 15, 52, 0.6); +} + +.cm-editor .h1.meta { + color: orange; +} + +.cm-editor .h2 { + font-size: 1.2em; + color: #fff; + font-weight: bold; +} + +.cm-editor .cm-line.line-h2 { + display: block; + background-color: rgba(0, 15, 52, 0.6); +} + +.cm-editor .h2.meta { + color: orange; +} + +.cm-editor .line-code { + background-color: #efefef; + margin-left: 30px; +} + +.cm-editor .line-fenced-code { + background-color: #efefef; +} + +.cm-editor .meta { + color: #520130; +} + +.cm-editor .line-blockquote { + background-color: #eee; + color: #676767; + text-indent: calc(-1 * (var(--ident) + 3px)); + padding-left: var(--ident); +} + +.cm-editor .emphasis { + font-style: italic; +} + +.cm-editor .strong { + font-weight: 900; +} + +.cm-editor .link:not(.meta, .url) { + color: #0330cb; + text-decoration: underline; +} + +.cm-editor .link.url { + color: #7e7d7d; +} + +.cm-editor .wiki-link { + color: #0330cb; + /*text-decoration: underline;*/ +} + +.cm-editor .mention { + color: gray; +} + +.cm-editor .tag { + color: #8d8d8d; +} + +.cm-editor .line-li { + text-indent: calc(-1 * var(--ident) - 3px); + margin-left: var(--ident); +} diff --git a/webapp/tsconfig.json b/webapp/tsconfig.json new file mode 100644 index 0000000..ded63c9 --- /dev/null +++ b/webapp/tsconfig.json @@ -0,0 +1,10 @@ +{ + "include": ["src/**/*"], + "compilerOptions": { + "target": "es2021", + "strict": true , + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "jsx": "react-jsx" + } + } \ No newline at end of file diff --git a/yarn.lock b/webapp/yarn.lock similarity index 76% rename from yarn.lock rename to webapp/yarn.lock index 8585d89..c92c8f9 100644 --- a/yarn.lock +++ b/webapp/yarn.lock @@ -320,95 +320,95 @@ dependencies: "@lezer/common" "^0.15.0" -"@parcel/bundler-default@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.3.1.tgz#2f29b77427b34523cd2c5c0d22a769f819cb564a" - integrity sha512-NFPI3UgWA3wD057ZXdoI9xM+JfM5aooPDJEvBateUQibwPzb96k9Bw7AfKnB/UAsASgtXeNAZXDqhXq5zrXeYQ== +"@parcel/bundler-default@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.3.2.tgz#329f171e210dfb22beaa52ae706ccde1dae384c1" + integrity sha512-JUrto4mjSD0ic9dEqRp0loL5o3HVYHja1ZIYSq+rBl2UWRV6/9cGTb07lXOCqqm0BWE+hQ4krUxB76qWaF0Lqw== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/hash" "2.3.1" - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/hash" "2.3.2" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" -"@parcel/cache@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.3.1.tgz#259da8fecdfaa2ae6d481338d264f2dd3c993c71" - integrity sha512-8Wvm0VERtocUepIfkZ6xVs1LHZqttnzdrM7oSc0bXhwtz8kZB++N88g0rQskbUchW87314eYdzBtEL0aiq0bgQ== +"@parcel/cache@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.3.2.tgz#ba8c2af02fd45b90c7bc6f829bfc566d1ded0a13" + integrity sha512-Xxq+ekgcFEme6Fn1v7rEOBkyMOUOUu7eNqQw0l6HQS+INZ2Q7YzzfdW7pI8rEOAAICVg5BWKpmBQZpgJlT+HxQ== dependencies: - "@parcel/fs" "2.3.1" - "@parcel/logger" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/fs" "2.3.2" + "@parcel/logger" "2.3.2" + "@parcel/utils" "2.3.2" lmdb "^2.0.2" -"@parcel/codeframe@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.3.1.tgz#7855498b51d43c19181d6cd6dc8177dab2c83f40" - integrity sha512-sdNvbg9qYS2pwzqyyyt+wZfNGuy7EslzDLbzQclFZmhD6e770mcYoi8/7i7D/AONbXiI15vwNmgOdcUIXtPxbA== +"@parcel/codeframe@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.3.2.tgz#73fb5a89910b977342808ca8f6ece61fa01b7690" + integrity sha512-ireQALcxxrTdIEpzTOoMo/GpfbFm1qlyezeGl3Hce3PMvHLg3a5S6u/Vcy7SAjdld5GfhHEqVY+blME6Z4CyXQ== dependencies: chalk "^4.1.0" -"@parcel/compressor-raw@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.3.1.tgz#04150d2e1e8a64bc446705d4aa2ec4ee3f806753" - integrity sha512-a294CarNzmy5mqTYnoO6clUxzVN/+HuUMAz1Y7EmsXwS6pJMCdhrE1Lra3upslFj4YMwp9N6+skzkptSCArkTQ== +"@parcel/compressor-raw@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.3.2.tgz#1a808ae9e61ed86f655935e1d2a984383b3c00a7" + integrity sha512-8dIoFwinYK6bOTpnZOAwwIv0v73y0ezsctPmfMnIqVQPn7wJwfhw/gbKVcmK5AkgQMkyid98hlLZoaZtGF1Mdg== dependencies: - "@parcel/plugin" "2.3.1" + "@parcel/plugin" "2.3.2" -"@parcel/config-default@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.3.1.tgz#5bcf1ffbc6638aa586340a376240c365644cc5fd" - integrity sha512-EEu8GPHAlHchyIu5AD1uPbOC/wPoAOS/ni2+yBmJWq3MJ6hwjnAdZJVYs8qVD9n2lcu3kcpO4vYxL8kv+i1mTQ== +"@parcel/config-default@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.3.2.tgz#3f21a37fa07b22de9cd6b1aea19bc310a02d4abb" + integrity sha512-E7/iA7fGCYvXU3u6zF9nxjeDVsgjCN6MVvDjymjaxYMoDWTIsPV245SBEXqzgtmzbMAV+VAl4rVWLMB4pzMt9g== dependencies: - "@parcel/bundler-default" "2.3.1" - "@parcel/compressor-raw" "2.3.1" - "@parcel/namer-default" "2.3.1" - "@parcel/optimizer-cssnano" "2.3.1" - "@parcel/optimizer-htmlnano" "2.3.1" - "@parcel/optimizer-image" "2.3.1" - "@parcel/optimizer-svgo" "2.3.1" - "@parcel/optimizer-terser" "2.3.1" - "@parcel/packager-css" "2.3.1" - "@parcel/packager-html" "2.3.1" - "@parcel/packager-js" "2.3.1" - "@parcel/packager-raw" "2.3.1" - "@parcel/packager-svg" "2.3.1" - "@parcel/reporter-dev-server" "2.3.1" - "@parcel/resolver-default" "2.3.1" - "@parcel/runtime-browser-hmr" "2.3.1" - "@parcel/runtime-js" "2.3.1" - "@parcel/runtime-react-refresh" "2.3.1" - "@parcel/runtime-service-worker" "2.3.1" - "@parcel/transformer-babel" "2.3.1" - "@parcel/transformer-css" "2.3.1" - "@parcel/transformer-html" "2.3.1" - "@parcel/transformer-image" "2.3.1" - "@parcel/transformer-js" "2.3.1" - "@parcel/transformer-json" "2.3.1" - "@parcel/transformer-postcss" "2.3.1" - "@parcel/transformer-posthtml" "2.3.1" - "@parcel/transformer-raw" "2.3.1" - "@parcel/transformer-react-refresh-wrap" "2.3.1" - "@parcel/transformer-svg" "2.3.1" + "@parcel/bundler-default" "2.3.2" + "@parcel/compressor-raw" "2.3.2" + "@parcel/namer-default" "2.3.2" + "@parcel/optimizer-cssnano" "2.3.2" + "@parcel/optimizer-htmlnano" "2.3.2" + "@parcel/optimizer-image" "2.3.2" + "@parcel/optimizer-svgo" "2.3.2" + "@parcel/optimizer-terser" "2.3.2" + "@parcel/packager-css" "2.3.2" + "@parcel/packager-html" "2.3.2" + "@parcel/packager-js" "2.3.2" + "@parcel/packager-raw" "2.3.2" + "@parcel/packager-svg" "2.3.2" + "@parcel/reporter-dev-server" "2.3.2" + "@parcel/resolver-default" "2.3.2" + "@parcel/runtime-browser-hmr" "2.3.2" + "@parcel/runtime-js" "2.3.2" + "@parcel/runtime-react-refresh" "2.3.2" + "@parcel/runtime-service-worker" "2.3.2" + "@parcel/transformer-babel" "2.3.2" + "@parcel/transformer-css" "2.3.2" + "@parcel/transformer-html" "2.3.2" + "@parcel/transformer-image" "2.3.2" + "@parcel/transformer-js" "2.3.2" + "@parcel/transformer-json" "2.3.2" + "@parcel/transformer-postcss" "2.3.2" + "@parcel/transformer-posthtml" "2.3.2" + "@parcel/transformer-raw" "2.3.2" + "@parcel/transformer-react-refresh-wrap" "2.3.2" + "@parcel/transformer-svg" "2.3.2" -"@parcel/core@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.3.1.tgz#d4f0092552b46f33ea21e45c78c5cd5c1399a214" - integrity sha512-Fzj8OxICQ0dKqu+haq1LP/yxmE1ryALIddZrgmn4JSoNiZVtPJMOxidozyl+3bnEq0mRyH5i38CDFRUWl9dqKQ== +"@parcel/core@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.3.2.tgz#1b9a79c1ff96dba5e0f53d4277bed4e7ab4590d0" + integrity sha512-gdJzpsgeUhv9H8T0UKVmyuptiXdduEfKIUx0ci+/PGhq8cCoiFnlnuhW6H7oLr79OUc+YJStabDJuG4U2A6ysw== dependencies: - "@parcel/cache" "2.3.1" - "@parcel/diagnostic" "2.3.1" - "@parcel/events" "2.3.1" - "@parcel/fs" "2.3.1" - "@parcel/graph" "2.3.1" - "@parcel/hash" "2.3.1" - "@parcel/logger" "2.3.1" - "@parcel/package-manager" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/cache" "2.3.2" + "@parcel/diagnostic" "2.3.2" + "@parcel/events" "2.3.2" + "@parcel/fs" "2.3.2" + "@parcel/graph" "2.3.2" + "@parcel/hash" "2.3.2" + "@parcel/logger" "2.3.2" + "@parcel/package-manager" "2.3.2" + "@parcel/plugin" "2.3.2" "@parcel/source-map" "^2.0.0" - "@parcel/types" "2.3.1" - "@parcel/utils" "2.3.1" - "@parcel/workers" "2.3.1" + "@parcel/types" "2.3.2" + "@parcel/utils" "2.3.2" + "@parcel/workers" "2.3.2" abortcontroller-polyfill "^1.1.9" base-x "^3.0.8" browserslist "^4.6.6" @@ -421,270 +421,270 @@ nullthrows "^1.1.1" semver "^5.7.1" -"@parcel/diagnostic@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.3.1.tgz#821040ab49c862463f47b44b8c7725b3ec3bf9bb" - integrity sha512-hBMcg4WVMdSIy6RpI4gSto5dZ3OoUbnrCZzVw3J1tzQJn7x9na/+014IaE58vJtAqJ8/jc/TqWIcwsSLe898rA== +"@parcel/diagnostic@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.3.2.tgz#1d3f0b55bfd9839c6f41d704ebbc89a96cca88dc" + integrity sha512-/xW93Az4AOiifuYW/c4CDbUcu3lx5FcUDAj9AGiR9NSTsF/ROC/RqnxvQ3AGtqa14R7vido4MXEpY3JEp6FsqA== dependencies: json-source-map "^0.6.1" nullthrows "^1.1.1" -"@parcel/events@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.3.1.tgz#77108bd706638831339b96eaab39a0e9137aa92e" - integrity sha512-J2rWKGl1Z2IvwwDwWYz/4gUxC1P4LsioUyOo1HYGT+N5+r41P8ZB5CM/aosI2qu5mMsH8rTpclOv5E36vCSQxw== +"@parcel/events@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.3.2.tgz#b6bcfbbc96d883716ee9d0e6ab232acdee862790" + integrity sha512-WiYIwXMo4Vd+pi58vRoHkul8TPE5VEfMY+3FYwVCKPl/LYqSD+vz6wMx9uG18mEbB1d/ofefv5ZFQNtPGKO4tQ== -"@parcel/fs-search@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.3.1.tgz#a97d5a98ec13bf47e636006c40eedf8031ede3d5" - integrity sha512-JsBIDttjmgJIMD6Q6MV83M+mwr5NqUm55iA+SewimboiWzSPzIJxRaegniSsNfsrBASJ6nSZFHcLPd/VJ5iqJw== +"@parcel/fs-search@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.3.2.tgz#18611877ac1b370932c71987c2ec0e93a4a7e53d" + integrity sha512-u3DTEFnPtKuZvEtgGzfVjQUytegSSn3POi7WfwMwPIaeDPfYcyyhfl+c96z7VL9Gk/pqQ99/cGyAwFdFsnxxXA== dependencies: detect-libc "^1.0.3" -"@parcel/fs@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.3.1.tgz#f60503921e1d3c17c6b43cf26fb76b08fe3fee2b" - integrity sha512-FKqyf8KF0zOw8gfj/feEAMj4Kzqkgt9Zxa2A7UDdMWRvxLR8znqnWjD++xqq6rxJp2Y1zm4fH3JOTK4CRddUSg== +"@parcel/fs@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.3.2.tgz#9628441a84c2582e1f6e69549feb0da0cc143e40" + integrity sha512-XV+OsnRpN01QKU37lBN0TFKvv7uPKfQGbqFqYOrMbXH++Ae8rBU0Ykz+Yu4tv2h7shMlde+AMKgRnRTAJZpWEQ== dependencies: - "@parcel/fs-search" "2.3.1" - "@parcel/types" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/fs-search" "2.3.2" + "@parcel/types" "2.3.2" + "@parcel/utils" "2.3.2" "@parcel/watcher" "^2.0.0" - "@parcel/workers" "2.3.1" + "@parcel/workers" "2.3.2" -"@parcel/graph@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.3.1.tgz#d7ae47a1784113c6aed2a5dfdd44f4a260e7ca8d" - integrity sha512-KdoPJM+d5LlCFZ46iapXXCwL+WD8/QYRkb/lFpmwHIT0xdY2sAU+rDFbSB3XeI8guol5zPZrGHSj38U1o+tSFA== +"@parcel/graph@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.3.2.tgz#4194816952ab322ab22a17f7d9ea17befbade64d" + integrity sha512-ltTBM3IEqumgmy4ABBFETT8NtAwSsjD9mY3WCyJ5P8rUshfVCg093rvBPbpuJYMaH/TV1AHVaWfZqaZ4JQDIQQ== dependencies: - "@parcel/utils" "2.3.1" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" -"@parcel/hash@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.3.1.tgz#7da61cd0a7358cabe9d6fdc4d103d6fb7b54526f" - integrity sha512-IYhSQE+CIKWjPfiLmsrXHupkNd+hMlTlI9DR5qLiD8ydyPwg0XE/bOYTcbdsSl6HTackY0XYVSJwTtEgvtYVfw== +"@parcel/hash@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.3.2.tgz#33b8ff04bb44f6661bdc1054b302ef1b6bd3acb3" + integrity sha512-SMtYTsHihws/wqdVnOr0QAGyGYsW9rJSJkkoRujUxo8l2ctnBN1ztv89eOUrdtgHsmcnj/oz1yw6sN38X+BUng== dependencies: detect-libc "^1.0.3" xxhash-wasm "^0.4.2" -"@parcel/logger@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.3.1.tgz#042f8742c6655ca01b5a64a041c228525e72c9c2" - integrity sha512-swNPInULCJrpCJCLOgZcf+xNcUF0NjD7LyNcB349BkyO7i6st14nfBjXf6eAJJu0z7RMmi6zp9CQB47e4cI6+g== +"@parcel/logger@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.3.2.tgz#b5fc7a9c1664ee0286d0f67641c7c81c8fec1561" + integrity sha512-jIWd8TXDQf+EnNWSa7Q10lSQ6C1LSH8OZkTlaINrfVIw7s+3tVxO3I4pjp7/ARw7RX2gdNPlw6fH4Gn/HvvYbw== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/events" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/events" "2.3.2" -"@parcel/markdown-ansi@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.3.1.tgz#076f9d4cdf5cc63e16eb1ddf36d799e8741e8063" - integrity sha512-M4Hi25pKtSh1KF/ppMDBk5QuLpYAQjgB/MSP+nz7NzXQlYPCN5oEk9TUkrmQ9J+vOvVwefxfy7ahSErEuQbTFw== +"@parcel/markdown-ansi@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.3.2.tgz#2a5be7ce76a506a9d238ea2257cb28e43abe4902" + integrity sha512-l01ggmag5QScCk9mYA0xHh5TWSffR84uPFP2KvaAMQQ9NLNufcFiU0mn/Mtr3pCb5L5dSzmJ+Oo9s7P1Kh/Fmg== dependencies: chalk "^4.1.0" -"@parcel/namer-default@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.3.1.tgz#987241fabd0398a5ce4cfea7e90316c381b614b3" - integrity sha512-huIb47vri76MhfuvmKtQqalqDfIwMfaPyjrbaoHysZ4fRUjvmrx0NPy0dNrTSLvA96iBc7EG2Zzw+Qn3voAiwg== +"@parcel/namer-default@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.3.2.tgz#84e17abfc84fd293b23b3f405280ed2e279c75d8" + integrity sha512-3QUMC0+5+3KMKfoAxYAbpZtuRqTgyZKsGDWzOpuqwemqp6P8ahAvNPwSCi6QSkGcTmvtYwBu9/NHPSONxIFOfg== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/plugin" "2.3.2" nullthrows "^1.1.1" -"@parcel/node-resolver-core@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.3.1.tgz#e9b2693b2e213893bb0705976d8131e21460a8ac" - integrity sha512-iEeilPoeiOyWLeF1NERZByOWe3IqUnNuoHkGbn8qZWlZXYO+k+w/X8Auv0KKsLVGe4XdljwsWbTWuhQJZ8BpIg== +"@parcel/node-resolver-core@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.3.2.tgz#dd360f405949fdcd62980cd44825052ab28f6135" + integrity sha512-wmrnMNzJN4GuHw2Ftho+BWgSWR6UCkW3XoMdphqcxpw/ieAdS2a+xYSosYkZgQZ6lGutSvLyJ1CkVvP6RLIdQQ== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" -"@parcel/optimizer-cssnano@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-cssnano/-/optimizer-cssnano-2.3.1.tgz#93d3ef0cd1ec07bd2df394bf4e796ef63e74e30d" - integrity sha512-e/YfTbMzn71CgSyyL/e+MZ/aQTPcUXoQ/EtqcuDlS3kcp2tw1aHgP0xmZT7dSPv+L+I0gY3aQSMM7IqgIzfkLQ== +"@parcel/optimizer-cssnano@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-cssnano/-/optimizer-cssnano-2.3.2.tgz#70758f6646fd4debc26a90ae7dddf398928c0ce1" + integrity sha512-wTBOxMiBI38NAB9XIlQZRCjS59+EWjWR9M04D3TWyxl+dL5gYMc1cl4GNynUnmcPdz+3s1UbOdo5/8V90wjiiw== dependencies: - "@parcel/plugin" "2.3.1" + "@parcel/plugin" "2.3.2" "@parcel/source-map" "^2.0.0" cssnano "^5.0.15" postcss "^8.4.5" -"@parcel/optimizer-htmlnano@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.3.1.tgz#7d6950c37e235ac3edbc18afaa57128d53c3cf2a" - integrity sha512-zE76grrE5KlWwooH9AnkKRU4QNgcWUtHpJUWba5JYXuCfaqCG2XpN5ARBmRqtmrEke7PlCt/1F0E47PPhZeWiw== +"@parcel/optimizer-htmlnano@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.3.2.tgz#4086736866621182f5dd1a8abe78e9f5764e1a28" + integrity sha512-U8C0TDSxsx8HmHaLW0Zc7ha1fXQynzhvBjCRMGYnOiLiw0MOfLQxzQ2WKVSeCotmdlF63ayCwxWsd6BuqStiKQ== dependencies: - "@parcel/plugin" "2.3.1" + "@parcel/plugin" "2.3.2" htmlnano "^2.0.0" nullthrows "^1.1.1" posthtml "^0.16.5" svgo "^2.4.0" -"@parcel/optimizer-image@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.3.1.tgz#f515510ad1fc940c2c62c4d0bfa7953539219e30" - integrity sha512-vBnyWaaqljASMi/vDkVdv855/G/BaJYzZklsc5xjGUwZq8nbH4sZPc9NDdl99/WU3yGR8QtA67BdTRkRLf8rKQ== +"@parcel/optimizer-image@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.3.2.tgz#0549cc1abc99fdd6f46bd44ce8551eb135e44d4f" + integrity sha512-HOk3r5qdvY/PmI7Q3i2qEgFH3kP2QWG4Wq3wmC4suaF1+c2gpiQc+HKHWp4QvfbH3jhT00c5NxQyqPhbXeNI9Q== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" - "@parcel/workers" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" + "@parcel/workers" "2.3.2" detect-libc "^1.0.3" -"@parcel/optimizer-svgo@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.3.1.tgz#728bd62b8b9a8714751255ef7de7ff5d964cd780" - integrity sha512-PwEXmmZ9z7WNs8n/lWkbwRdw62MJqYzKDUUJPF+KCQb7NG1OAZy1jVj+TyiCuMtxIKhNtei8OrMOlvulQgixcg== +"@parcel/optimizer-svgo@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.3.2.tgz#ebf2f48f356ad557d2bbfae361520d3d29bc1c37" + integrity sha512-l7WvZ5+e7D1mVmLUxMVaSb29cviXzuvSY2OpQs0ukdPACDqag+C65hWMzwTiOSSRGPMIu96kQKpeVru2YjibhA== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" svgo "^2.4.0" -"@parcel/optimizer-terser@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.3.1.tgz#02416f9d7487671d2d0759944929417b87b6dd65" - integrity sha512-uDJghBgwCKhq6m1y/vw/tRZKS4kqNXhXaZIYtEyRdrxJ/pqGTGmHVYO5ItXpgGugM49C8TrqVVlcgIIgR/p1yw== +"@parcel/optimizer-terser@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.3.2.tgz#790b69e6ecc6ef0d8f25b57e9a13806e1f1c2943" + integrity sha512-dOapHhfy0xiNZa2IoEyHGkhhla07xsja79NPem14e5jCqY6Oi40jKNV4ab5uu5u1elWUjJuw69tiYbkDZWbKQw== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/plugin" "2.3.2" "@parcel/source-map" "^2.0.0" - "@parcel/utils" "2.3.1" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" terser "^5.2.0" -"@parcel/package-manager@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.3.1.tgz#c0f49fab9d1108bc9bf8d4357c53eead8d28c48d" - integrity sha512-w2XOkD3SU8RxhUDW+Soy/TjvEVvfUsBmHy02asllt4b/ZtyZVAsQmonGExHDDkRn3TNDR6Y96Yw6M7purt+b9w== +"@parcel/package-manager@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.3.2.tgz#380f0741c9d0c79c170c437efae02506484df315" + integrity sha512-pAQfywKVORY8Ee+NHAyKzzQrKbnz8otWRejps7urwhDaTVLfAd5C/1ZV64ATZ9ALYP9jyoQ8bTaxVd4opcSuwg== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/fs" "2.3.1" - "@parcel/logger" "2.3.1" - "@parcel/types" "2.3.1" - "@parcel/utils" "2.3.1" - "@parcel/workers" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/fs" "2.3.2" + "@parcel/logger" "2.3.2" + "@parcel/types" "2.3.2" + "@parcel/utils" "2.3.2" + "@parcel/workers" "2.3.2" semver "^5.7.1" -"@parcel/packager-css@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.3.1.tgz#9060ed5aaefab88bcea7cc004531144dacb67252" - integrity sha512-gvrGNw4tiIyi6SO7at7RJvfCDQIAuy9xJhFtuouuFAl6A1EMhkoL5amcmavfdbN166LJ/3s74t1LYoPeYCnb2Q== +"@parcel/packager-css@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.3.2.tgz#4994d872449843c1c0cda524b6df3327e2f0a121" + integrity sha512-ByuF9xDnQnpVL1Hdu9aY6SpxOuZowd3TH7joh1qdRPLeMHTEvUywHBXoiAyNdrhnLGum8uPEdY8Ra5Xuo1U7kg== dependencies: - "@parcel/plugin" "2.3.1" + "@parcel/plugin" "2.3.2" "@parcel/source-map" "^2.0.0" - "@parcel/utils" "2.3.1" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" -"@parcel/packager-html@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.3.1.tgz#4cdbf9536680dc6455cd2f9547dbd3b553c6bd67" - integrity sha512-dOPEB0KEyLzDl5zEXjRCo/J/fsc1wVw0gUa+N0A5LAZeYmTOPJgTHhb/ZeNcPKWQT75eGUSEaDXX+oBs1B17xw== +"@parcel/packager-html@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.3.2.tgz#e54085fbaa49bed4258ffef80bc36b421895965f" + integrity sha512-YqAptdU+uqfgwSii76mRGcA/3TpuC6yHr8xG+11brqj/tEFLsurmX0naombzd7FgmrTE9w+kb0HUIMl2vRBn0A== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/types" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/types" "2.3.2" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" posthtml "^0.16.5" -"@parcel/packager-js@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.3.1.tgz#4d41163d53287b42e48a85d29cde0aa4273db26f" - integrity sha512-7TikegHYgwiuUQ9bFikG3H47wTms7nVpDQEwBYHmPhDLvwlKCq17HJ39eQKS4740G6umIvQkG5t7mcR1XTXYtg== +"@parcel/packager-js@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.3.2.tgz#2d2566bde0da921042b79aa827c71109665d795c" + integrity sha512-3OP0Ro9M1J+PIKZK4Ec2N5hjIPiqk++B2kMFeiUqvaNZjJgKrPPEICBhjS52rma4IE/NgmIMB3aI5pWqE/KwNA== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/hash" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/hash" "2.3.2" + "@parcel/plugin" "2.3.2" "@parcel/source-map" "^2.0.0" - "@parcel/utils" "2.3.1" + "@parcel/utils" "2.3.2" globals "^13.2.0" nullthrows "^1.1.1" -"@parcel/packager-raw@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.3.1.tgz#b8672852c8b70688ba99adfc04f0b110ade72a8a" - integrity sha512-Gy4WfZPy64+E7Gvvdw3/HG5EFzuBbC64MbLv0AgQNIDub5LG76dPdLLgJ/TS72gXsA43Q2ApaXMHBOC/G0yECA== +"@parcel/packager-raw@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.3.2.tgz#869cc3e7bee8ff3655891a0af400cf4e7dd4f144" + integrity sha512-RnoZ7WgNAFWkEPrEefvyDqus7xfv9XGprHyTbfLittPaVAZpl+4eAv43nXyMfzk77Cgds6KcNpkosj3acEpNIQ== dependencies: - "@parcel/plugin" "2.3.1" + "@parcel/plugin" "2.3.2" -"@parcel/packager-svg@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.3.1.tgz#523e4956172a31701ea62e54ccbed9559920b12b" - integrity sha512-lUx+DXymTNKhvxdoNhnb6or4qjGLbXBTAiyfp4q8QlFXJHKVbEEoVgLc9rda9TLIG18Pn4NR9QE+o/nyzwcibQ== +"@parcel/packager-svg@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.3.2.tgz#a7a02e22642ae93f42b8bfd7d122b4a159988743" + integrity sha512-iIC0VeczOXynS7M5jCi3naMBRyAznBVJ3iMg92/GaI9duxPlUMGAlHzLAKNtoXkc00HMXDH7rrmMb04VX6FYSg== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/types" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/types" "2.3.2" + "@parcel/utils" "2.3.2" posthtml "^0.16.4" -"@parcel/plugin@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.3.1.tgz#d7abc685ede4d7ae25bb15ccfcfa2a59e8d7c51d" - integrity sha512-ROOWbgFze7BCF3RkEh8VbcKGlR5UGBuJ8lfCaFrG1VOk7Rxgl8Bmk96TRbZREm/1jB74p2O8twVKyPSC13riow== +"@parcel/plugin@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.3.2.tgz#7701c40567d2eddd5d5b2b6298949cd03a2a22fa" + integrity sha512-SaLZAJX4KH+mrAmqmcy9KJN+V7L+6YNTlgyqYmfKlNiHu7aIjLL+3prX8QRcgGtjAYziCxvPj0cl1CCJssaiGg== dependencies: - "@parcel/types" "2.3.1" + "@parcel/types" "2.3.2" -"@parcel/reporter-cli@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.3.1.tgz#2ef604b82e02136901ac48fb0333ee1feb13f0f0" - integrity sha512-rLDxD1SJIiAhd/N3CiRiNKz/NVVyh25tPEOFCNFgoTVC8wJKfzeUEgVuTJQ8lRLrzk0PfY51KyGmWdLqti8jag== +"@parcel/reporter-cli@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.3.2.tgz#0617e088aac5ef7fa255d088e7016bb4f9d66a53" + integrity sha512-VYetmTXqW83npsvVvqlQZTbF3yVL3k/FCCl3kSWvOr9LZA0lmyqJWPjMHq37yIIOszQN/p5guLtgCjsP0UQw1Q== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/types" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/types" "2.3.2" + "@parcel/utils" "2.3.2" chalk "^4.1.0" -"@parcel/reporter-dev-server@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.3.1.tgz#16fcc6b1fb5ebefcefe7c860d363817940289dc1" - integrity sha512-ramEx+dFMcgqus2We7jlonQgCo3/xwnjdXUsC+iuJXSKGW7eMCZ5f+fjETkeq2eOt8YYzAML54u7Qkt1gSX39Q== +"@parcel/reporter-dev-server@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.3.2.tgz#46ee4c53ad08c8b8afd2c79fb37381b6ba55cfb5" + integrity sha512-E7LtnjAX4iiWMw2qKUyFBi3+bDz0UGjqgHoPQylUYYLi6opXjJz/oC+cCcCy4e3RZlkrl187XonvagS59YjDxA== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" -"@parcel/resolver-default@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.3.1.tgz#42df17878f2e1dcccaf5821f2341b78c8e877d2c" - integrity sha512-fScU5ZG/VmdqoqPPArTLHXC7LgsfSVKA6mpZpkpkAyFTMZimPv6HuFwMhIj7jabeWRQKShjpT07Ygq31UBl/Cw== +"@parcel/resolver-default@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.3.2.tgz#286070412ad7fe506f7c88409f39b362d2041798" + integrity sha512-y3r+xOwWsATrNGUWuZ6soA7q24f8E5tY1AZ9lHCufnkK2cdKZJ5O1cyd7ohkAiKZx2/pMd+FgmVZ/J3oxetXkA== dependencies: - "@parcel/node-resolver-core" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/node-resolver-core" "2.3.2" + "@parcel/plugin" "2.3.2" -"@parcel/runtime-browser-hmr@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.3.1.tgz#4d5951af7774f96c74227ae9242f179ee7542696" - integrity sha512-Zd6fzBaNNhLBqROy1Jtwsddf5/E2I7zVecHPWutAUT9L4xX3XMH7Yv3W6vmLLq3X0mdfmoRtVnQseAMPAyfNog== +"@parcel/runtime-browser-hmr@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.3.2.tgz#cb23a850324ea792168438a9be6a345ebb66eb6d" + integrity sha512-nRD6uOyF1+HGylP9GASbYmvUDOsDaNwvaxuGTSh8+5M0mmCgib+hVBiPEKbwdmKjGbUPt9wRFPyMa/JpeQZsIQ== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" -"@parcel/runtime-js@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.3.1.tgz#b70d47bf35b67253dec36b166e76d4fd92f837a6" - integrity sha512-Nmgbo+v5p5g1DSHbmZni22ZsHhcAsi7z6Qk9cdXrt/fW2VbQRu+yBKebeinwUnWGd5Lwu5UZ2mwn2nSaSV8Spw== +"@parcel/runtime-js@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.3.2.tgz#c0e14251ce43f95977577e23bb9ac5c2487f3bb1" + integrity sha512-SJepcHvYO/7CEe/Q85sngk+smcJ6TypuPh4D2R8kN+cAJPi5WvbQEe7+x5BEgbN+5Jumi/Uo3FfOOE5mYh+F6g== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" -"@parcel/runtime-react-refresh@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.3.1.tgz#b7e31e177316b7300e08c79e7316996fe58de73b" - integrity sha512-42ldT80UZ8fqm0M5td3YviBn6fFYwcva3PdWLfwC5b1woug/5/FevMna+ndNBSFjt+xbFLUFf6bDxnV7vlWHHw== +"@parcel/runtime-react-refresh@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.3.2.tgz#11961d7429ae3333b7efe14c4f57515df57eb5f2" + integrity sha512-P+GRPO2XVDSBQ4HmRSj2xfbHSQvL9+ahTE/AB74IJExLTITv5l4SHAV3VsiKohuHYUAYHW3A/Oe7tEFCAb6Cug== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" react-refresh "^0.9.0" -"@parcel/runtime-service-worker@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.3.1.tgz#8181c8915c3f293e9baa37904dd728f95dff33a5" - integrity sha512-kTt1DqMIQt5eNAJZTxeegLgGxHC4qXSaBrfQanezp+1fmRi1TOWvKgM7lzKwY9IaXfyCV/DR+Wy95iR6r1P70A== +"@parcel/runtime-service-worker@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.3.2.tgz#aa91797e57d1bb5b2aac04ac62c5410709ae0a27" + integrity sha512-iREHj/eapphC4uS/zGUkiTJvG57q+CVbTrfE42kB8ECtf/RYNo5YC9htdvPZjRSXDPrEPc5NCoKp4X09ENNikw== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" "@parcel/source-map@^2.0.0": @@ -694,67 +694,67 @@ dependencies: detect-libc "^1.0.3" -"@parcel/transformer-babel@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.3.1.tgz#0d0a99f6f55b99130ec55dfdba736fb746bae95e" - integrity sha512-KEyuFNQJYFMP39XvhTu2ZzsD+gdQKyA3X+5DViH2bSgZeEjCIfAhAjg7mSfKeD/u8ZVBmIDq2M/QjDO+taM0KQ== +"@parcel/transformer-babel@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.3.2.tgz#2d8c0d1f95d9747936d132dc4c34edb0b6b80d39" + integrity sha512-QpWfH2V6jJ+kcUBIMM/uBBG8dGFvNaOGS+8jD6b+eTP+1owzm83RoWgqhRV2D/hhv2qMXEQzIljoc/wg2y+X4g== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/plugin" "2.3.2" "@parcel/source-map" "^2.0.0" - "@parcel/utils" "2.3.1" + "@parcel/utils" "2.3.2" browserslist "^4.6.6" json5 "^2.2.0" nullthrows "^1.1.1" semver "^5.7.0" -"@parcel/transformer-css@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.3.1.tgz#1afa8428744ec9f5e3434a24b4564dfe4734196b" - integrity sha512-InuEbSu7yLp3jjnmVB0MzO8WjG0123EJqGVVlB5WbEBUxzLN3bgTJDKP5O7xGgipjhNIpFUjx2SU7eeSb6iFog== +"@parcel/transformer-css@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.3.2.tgz#968826e42d7cac9963dc0a67a30d393ef996e48c" + integrity sha512-8lzvDny+78DIAqhcXam2Bf9FyaUoqzHdUQdNFn+PuXTHroG/QGPvln1kvqngJjn4/cpJS9vYmAPVXe+nai3P8g== dependencies: - "@parcel/hash" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/hash" "2.3.2" + "@parcel/plugin" "2.3.2" "@parcel/source-map" "^2.0.0" - "@parcel/utils" "2.3.1" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" postcss "^8.4.5" postcss-value-parser "^4.2.0" semver "^5.7.1" -"@parcel/transformer-html@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.3.1.tgz#5a9d67f152e88225c27a1a6f63c91e0370ca8103" - integrity sha512-23Z7kuSDnLzB8Du88pua2VjgOh7ZUpW1hedX1FubV2PfUGpZvAg7XBTdTGp+7Tmy8PIGyZrP3CP1UNQkjLO8bQ== +"@parcel/transformer-html@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.3.2.tgz#c240f09369445d287d16beba207407c925532d90" + integrity sha512-idT1I/8WM65IFYBqzRwpwT7sf0xGur4EDQDHhuPX1w+pIVZnh0lkLMAnEqs6ar1SPRMys4chzkuDNnqh0d76hg== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/hash" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/hash" "2.3.2" + "@parcel/plugin" "2.3.2" nullthrows "^1.1.1" posthtml "^0.16.5" posthtml-parser "^0.10.1" posthtml-render "^3.0.0" semver "^5.7.1" -"@parcel/transformer-image@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.3.1.tgz#bca475174d27698aa0cdd58a428914929ce6d59e" - integrity sha512-8A+XnUhDnEAbfc7GCBRvCsSiv/6Ro5+vd1sZ5tQJmajcc0nfIbolZQuztEHZMDPjEr+WIcOCJZ5re5bCG3NhZA== +"@parcel/transformer-image@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.3.2.tgz#24b6eda51a6b07c195886bbb67fb2ade14c325f3" + integrity sha512-0K7cJHXysli6hZsUz/zVGO7WCoaaIeVdzAxKpLA1Yl3LKw/ODiMyXKt08LiV/ljQ2xT5qb9EsXUWDRvcZ0b96A== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/workers" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/workers" "2.3.2" nullthrows "^1.1.1" -"@parcel/transformer-js@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.3.1.tgz#9601d1a724e95ba0c78d1d948887e979bf71f68c" - integrity sha512-9mHpfw008l00cW8QW21Nhfax/aOqZ+CozNXj5gWV0uJ9is5x0TumKYXtYUsuP9LunAra/ZenvpQjCFibTXe51Q== +"@parcel/transformer-js@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.3.2.tgz#24bcb488d5f82678343a5630fe4bbe822789ac33" + integrity sha512-U1fbIoAoqR5P49S+DMhH8BUd9IHRPwrTTv6ARYGsYnhuNsjTFhNYE0kkfRYboe/e0z7vEbeJICZXjnZ7eQDw5A== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/plugin" "2.3.2" "@parcel/source-map" "^2.0.0" - "@parcel/utils" "2.3.1" - "@parcel/workers" "2.3.1" + "@parcel/utils" "2.3.2" + "@parcel/workers" "2.3.2" "@swc/helpers" "^0.2.11" browserslist "^4.6.6" detect-libc "^1.0.3" @@ -762,96 +762,114 @@ regenerator-runtime "^0.13.7" semver "^5.7.1" -"@parcel/transformer-json@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.3.1.tgz#d41e55dbfa3e1ffa49ad761889b8518a1db1cdf1" - integrity sha512-usaoro1uH5hxI57x7Qve4Y6Tsf5GitVh6gC3e5TaJFc3mnr5pn3KKviWC0g0haeluv9NCPK++alQuzmpgIooWQ== +"@parcel/transformer-json@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.3.2.tgz#4c470e86659e87ee13b1f31e75a3621d3615b6bd" + integrity sha512-Pv2iPaxKINtFwOk5fDbHjQlSm2Vza/NLimQY896FLxiXPNAJxWGvMwdutgOPEBKksxRx9LZPyIOHiRVZ0KcA3w== dependencies: - "@parcel/plugin" "2.3.1" + "@parcel/plugin" "2.3.2" json5 "^2.2.0" -"@parcel/transformer-postcss@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.3.1.tgz#04719566cbd298bd9b4fa581996bfeff5b6af224" - integrity sha512-rpoEGpStj1THw/NH3CuujrKan84h6SEnDBem8l/GAE7/cRDQs/O/JnJKP+oXcKOGH1KNdcuPWYb8ORW9Pe+Z5w== +"@parcel/transformer-postcss@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.3.2.tgz#a428c81569dd66758c5fab866dca69b4c6e59743" + integrity sha512-Rpdxc1rt2aJFCh/y/ccaBc9J1crDjNY5o44xYoOemBoUNDMREsmg5sR5iO81qKKO5GxfoosGb2zh59aeTmywcg== dependencies: - "@parcel/hash" "2.3.1" - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/hash" "2.3.2" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" clone "^2.1.1" nullthrows "^1.1.1" postcss-value-parser "^4.2.0" semver "^5.7.1" -"@parcel/transformer-posthtml@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.3.1.tgz#b187b0a59fd9a53e0f6866af20792de15207d9a5" - integrity sha512-ahFLfV8zdm6lH6gGSZxgUvFbP0qsclucV53ubRIRV+croGp1KhMCstbMY5GKGYHWoI6RRrxnbriJwVcbX9tUVQ== +"@parcel/transformer-posthtml@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.3.2.tgz#5da3f24bf240c3c49b2fdb17dcda5988d3057a30" + integrity sha512-tMdVExfdM+1G8A9KSHDsjg+S9xEGbhH5mApF2NslPnNZ4ciLKRNuHU2sSV/v8i0a6kacKvDTrwQXYBQJGOodBw== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" nullthrows "^1.1.1" posthtml "^0.16.5" posthtml-parser "^0.10.1" posthtml-render "^3.0.0" semver "^5.7.1" -"@parcel/transformer-raw@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.3.1.tgz#e25047005483a6b4487876d93532ef43feda2ab0" - integrity sha512-45ObmhBJ2wdlOGTsIEy9T+FOoQWY+x8HN2Cw9/ZhMWOpLtof56om5xk5u7hmsMMe/4Jaqxzkw3vInqOJR6bc1Q== +"@parcel/transformer-raw@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.3.2.tgz#40d21773e295bae3b16bfe7a89e414ccf534b9c5" + integrity sha512-lY7eOCaALZ90+GH+4PZRmAPGQRXoZ66NakSdhEtH6JSSAYOmZKDvNLGTMRo/vK1oELzWMuAHGdqvbcPDtNLLVw== dependencies: - "@parcel/plugin" "2.3.1" + "@parcel/plugin" "2.3.2" -"@parcel/transformer-react-refresh-wrap@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.3.1.tgz#ec5cbb08060ade427dfad87d2aab334ccac4b715" - integrity sha512-4uufhCCneMFpx6YaP2/ae/Ilpna5GSYuUXijlFHy4qcAIYkdtrHWRJuLBUBD4qktkmG22wTWgRwGHMk4seRDzg== +"@parcel/transformer-react-refresh-wrap@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.3.2.tgz#43ecfe6f4567b88abb81db9fe56b8d860d6a69f7" + integrity sha512-FZaderyCExn0SBZ6D+zHPWc8JSn9YDcbfibv0wkCl+D7sYfeWZ22i7MRp5NwCe/TZ21WuxDWySCggEp/Waz2xg== dependencies: - "@parcel/plugin" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/plugin" "2.3.2" + "@parcel/utils" "2.3.2" react-refresh "^0.9.0" -"@parcel/transformer-svg@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.3.1.tgz#1e9183d28a0d4702746d4f43e8fd0bd6055707f1" - integrity sha512-3V9LIpR+p8NEr8rnHHIa9PKUwQ4fEkhSo0S8g+FH32/f7y6IMuTy7hn0leYdfATNVi1Nx7d4boN4XSyUuORQfw== +"@parcel/transformer-svg@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.3.2.tgz#9a66aef5011c7bbb1fa3ce9bb52ca56d8f0f964d" + integrity sha512-k9My6bePsaGgUh+tidDjFbbVgKPTzwCAQfoloZRMt7y396KgUbvCfqDruk04k6k+cJn7Jl1o/5lUpTEruBze7g== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/hash" "2.3.1" - "@parcel/plugin" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/hash" "2.3.2" + "@parcel/plugin" "2.3.2" nullthrows "^1.1.1" posthtml "^0.16.5" posthtml-parser "^0.10.1" posthtml-render "^3.0.0" semver "^5.7.1" -"@parcel/types@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.3.1.tgz#50e34487a060dc6c5366ef8c23db5093cf441b5c" - integrity sha512-i2UyUoA4DzyYxe9rZRDuMAZ6TD3Mq3tTTqeJ2/zA6w83Aon3cqdE9va91peu1fKRGyRqE5lwWRtA7ktF1A2SVA== +"@parcel/ts-utils@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/ts-utils/-/ts-utils-2.3.2.tgz#d63f7027574f3c1a128e1c865d683d6aacb4476d" + integrity sha512-jYCHoSmU+oVtFA4q0BygVf74FpVnCDSNtVfLzd1EfGVHlBFMo9GzSY5luMTG4qhnNCDEEco89bkMIgjPHQ3qnA== dependencies: - "@parcel/cache" "2.3.1" - "@parcel/diagnostic" "2.3.1" - "@parcel/fs" "2.3.1" - "@parcel/package-manager" "2.3.1" + nullthrows "^1.1.1" + +"@parcel/types@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.3.2.tgz#7eb6925bc852a518dd75b742419e51292418769f" + integrity sha512-C77Ct1xNM7LWjPTfe/dQ/9rq1efdsX5VJu2o8/TVi6qoFh64Wp/c5/vCHwKInOTBZUTchVO6z4PGJNIZoUVJuA== + dependencies: + "@parcel/cache" "2.3.2" + "@parcel/diagnostic" "2.3.2" + "@parcel/fs" "2.3.2" + "@parcel/package-manager" "2.3.2" "@parcel/source-map" "^2.0.0" - "@parcel/workers" "2.3.1" + "@parcel/workers" "2.3.2" utility-types "^3.10.0" -"@parcel/utils@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.3.1.tgz#e1e582c850e7f7b131292cb45b8a177f59903413" - integrity sha512-OFdh/HuAcce753/U3QoORzYU3N5oZqCfQNRb0i3onuz/qpli5TyxUl/k1BuTqlKYr6Px3kj05g6GFi9kRBOMbw== +"@parcel/utils@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.3.2.tgz#4aab052fc9f3227811a504da7b9663ca75004f55" + integrity sha512-xzZ+0vWhrXlLzGoz7WlANaO5IPtyWGeCZruGtepUL3yheRWb1UU4zFN9xz7Z+j++Dmf1Fgkc3qdk/t4O8u9HLQ== dependencies: - "@parcel/codeframe" "2.3.1" - "@parcel/diagnostic" "2.3.1" - "@parcel/hash" "2.3.1" - "@parcel/logger" "2.3.1" - "@parcel/markdown-ansi" "2.3.1" + "@parcel/codeframe" "2.3.2" + "@parcel/diagnostic" "2.3.2" + "@parcel/hash" "2.3.2" + "@parcel/logger" "2.3.2" + "@parcel/markdown-ansi" "2.3.2" "@parcel/source-map" "^2.0.0" chalk "^4.1.0" +"@parcel/validator-typescript@^2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/validator-typescript/-/validator-typescript-2.3.2.tgz#4372c3e459106c2ed36fb6e66e0253227d0c88d4" + integrity sha512-IGGYx35lnblHwpIOWUZJusyIcn2a9L7pZmwnKXKDPONUP3lgHhbCv6Ix2WBwTRb+AztNBvXudR5PytBJ4DrovA== + dependencies: + "@parcel/diagnostic" "2.3.2" + "@parcel/plugin" "2.3.2" + "@parcel/ts-utils" "2.3.2" + "@parcel/types" "2.3.2" + "@parcel/utils" "2.3.2" + "@parcel/watcher@^2.0.0": version "2.0.5" resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.5.tgz#f913a54e1601b0aac972803829b0eece48de215b" @@ -860,15 +878,15 @@ node-addon-api "^3.2.1" node-gyp-build "^4.3.0" -"@parcel/workers@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.3.1.tgz#f0bfbd61785bea0667908989878fdf2d953c17e3" - integrity sha512-e2P/9p5AYBLfNRs8n+57ChGrn5171oHwY54dz/jj0CrXKN1q0b+rNwzYsPaAtOicBoqmm1s5I3cjfO6GfJP65A== +"@parcel/workers@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.3.2.tgz#05ffa2da9169bfb83335892c2b8abce55686ceb1" + integrity sha512-JbOm+Ceuyymd1SuKGgodC2EXAiPuFRpaNUSJpz3NAsS3lVIt2TDAPMOWBivS7sML/KltspUfl/Q9YwO0TPUFNw== dependencies: - "@parcel/diagnostic" "2.3.1" - "@parcel/logger" "2.3.1" - "@parcel/types" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/diagnostic" "2.3.2" + "@parcel/logger" "2.3.2" + "@parcel/types" "2.3.2" + "@parcel/utils" "2.3.2" chrome-trace-event "^1.0.2" nullthrows "^1.1.1" @@ -887,6 +905,32 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/prop-types@*": + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + +"@types/react-dom@^17.0.11": + version "17.0.11" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466" + integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^17.0.39": + version "17.0.39" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" + integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + abortcontroller-polyfill@^1.1.9: version "1.7.3" resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz#1b5b487bd6436b5b764fd52a612509702c3144b5" @@ -1128,6 +1172,11 @@ csso@^4.2.0: dependencies: css-tree "^1.1.2" +csstype@^3.0.2: + version "3.0.10" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" + integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== + detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" @@ -1264,7 +1313,7 @@ is-json@^2.0.1: resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff" integrity sha1-a+Fm0USCihMdaGiRuYPfYsOUkf8= -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -1317,6 +1366,13 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -1384,26 +1440,31 @@ nullthrows@^1.1.1: resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + ordered-binary@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.2.4.tgz#51d3a03af078a0bdba6c7bc8f4fedd1f5d45d83e" integrity sha512-A/csN0d3n+igxBPfUrjbV5GC69LWj2pjZzAAeeHXLukQ4+fytfP4T1Lg0ju7MSPSwq7KtHkGaiwO8URZN5IpLg== -parcel@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.3.1.tgz#0366556933e92f345d455f0f2fe6429c1d197b63" - integrity sha512-YDzKpWcO1tEqk7ENPTitE8zbDfYDjo7nsoT7Oun+7eZadwsiNds1+mbhCO0exGq4SJekto+dkMdrLMcbOWJznQ== +parcel@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.3.2.tgz#d1cb475f27edae981edea7a7104e04d3a35a87ca" + integrity sha512-4jhgoBcQaiGKmnmBvNyKyOvZrxCgzgUzdEoVup/fRCOP99hNmvYIN5IErIIJxsU9ObcG/RGCFF8wa4kVRsWfIg== dependencies: - "@parcel/config-default" "2.3.1" - "@parcel/core" "2.3.1" - "@parcel/diagnostic" "2.3.1" - "@parcel/events" "2.3.1" - "@parcel/fs" "2.3.1" - "@parcel/logger" "2.3.1" - "@parcel/package-manager" "2.3.1" - "@parcel/reporter-cli" "2.3.1" - "@parcel/reporter-dev-server" "2.3.1" - "@parcel/utils" "2.3.1" + "@parcel/config-default" "2.3.2" + "@parcel/core" "2.3.2" + "@parcel/diagnostic" "2.3.2" + "@parcel/events" "2.3.2" + "@parcel/fs" "2.3.2" + "@parcel/logger" "2.3.2" + "@parcel/package-manager" "2.3.2" + "@parcel/reporter-cli" "2.3.2" + "@parcel/reporter-dev-server" "2.3.2" + "@parcel/utils" "2.3.2" chalk "^4.1.0" commander "^7.0.0" get-port "^4.2.0" @@ -1676,11 +1737,28 @@ posthtml@^0.16.4, posthtml@^0.16.5: posthtml-parser "^0.10.0" posthtml-render "^3.0.0" +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + react-refresh@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + regenerator-runtime@^0.13.7: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" @@ -1696,6 +1774,14 @@ safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -1788,6 +1874,11 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +typescript@>=3.0.0: + version "4.5.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" + integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== + util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"