Skip to content

Commit

Permalink
feat: add component
Browse files Browse the repository at this point in the history
  • Loading branch information
r74tech committed May 26, 2023
1 parent 0bce511 commit 5293810
Show file tree
Hide file tree
Showing 70 changed files with 5,256 additions and 422 deletions.
3 changes: 3 additions & 0 deletions modules/ftml-components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# ftml-components

Custom elements and components for FTML.
20 changes: 20 additions & 0 deletions modules/ftml-components/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@wikijump/ftml-components",
"license": "agpl-3.0-or-later",
"description": "Web-components for FTML",
"version": "0.0.0",
"keywords": [
"wikijump"
],
"private": true,
"scripts": {},
"type": "module",
"main": "src/index.ts",
"dependencies": {
"@popperjs/core": "^2.11.5",
"@wikijump/dom": "workspace:*",
"@wikijump/prism": "workspace:*",
"@wikijump/util": "workspace:*",
"hfmath": "^0.0.2"
}
}
83 changes: 83 additions & 0 deletions modules/ftml-components/src/_base.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* TOP-LEVEL */

.wj-body * {
box-sizing: border-box;
}

/* MODIFIERS */

.wj-hidden {
display: none;
}

.wj-invisible {
visibility: hidden;
}

/* ALIGNMENT */

.wj-align-left {
padding-left: 0;
text-align: left;
}

.wj-align-right {
padding-right: 0;
text-align: right;
}

.wj-align-center {
text-align: center;
}

.wj-align-justify {
text-align: justify;
}

.wj-float-left {
float: left;
padding-left: 0;
}

.wj-float-right {
float: right;
padding-right: 0;
}

/* CLEAR FLOAT */

.wj-clear-float-left {
clear: left;
}

.wj-clear-float-right {
clear: right;
}

.wj-clear-float-both {
clear: both;
}

/* TABLE OF CONTENTS */

#wj-toc-list ul {
list-style: none;
}

/* MISCELLANEOUS */

.wj-email {
white-space: nowrap;
}

.wj-raw {
white-space: pre-wrap;
}

.wj-error-block {
display: block;
}

.wj-error-inline {
display: inline-block;
}
8 changes: 8 additions & 0 deletions modules/ftml-components/src/_default.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* DIVS */

.wiki-note {
width: auto;
margin: 0.5em 5em;
text-align: center;
border: 1px solid #999;
}
69 changes: 69 additions & 0 deletions modules/ftml-components/src/components/code/_code.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
.wj-code {
position: relative;
display: block;

pre {
display: block;
padding: 0;
margin: 0;
hyphens: none;
line-height: 1.5;
text-align: start;
word-break: normal;
word-wrap: normal;
tab-size: 4;
white-space: pre;
cursor: text;
contain: content;
}

code {
display: block;
overflow-x: auto;
user-select: contain;
}
}

.wj-code-panel {
position: absolute;
top: 0;
right: 0;
left: 0;
display: flex;
flex-direction: row-reverse;
align-items: center;
}

.wj-code-language {
user-select: none;
}

.wj-code-copy {
position: relative;
z-index: $z-above;
width: 2em;
height: 2em;
cursor: pointer;

> .wj-sprite {
position: absolute;
top: 50%;
left: 50%;
width: 1.5em;
height: 1.5em;
transform: translate(-50%, -50%);
}

> .sprite-wj-clipboard-success {
display: none;
}

&.wj-code-copy-success {
.sprite-wj-clipboard {
display: none;
}
.sprite-wj-clipboard-success {
display: block;
}
}
}
122 changes: 122 additions & 0 deletions modules/ftml-components/src/components/code/code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { addElement, BaseButton, observe, pauseObservation } from "@wikijump/dom"
import Prism from "@wikijump/prism"
import { animationFrame, timeout } from "@wikijump/util"

/**
* FTML `[[code]]` element. Automatically highlights the contents of its
* `<code>` child with Prism.
*/
export class CodeElement extends HTMLElement {
static tag = "wj-code"

/** Observer for watching changes to the contents of the code element. */
declare observer: MutationObserver

/** The language highlighting is being done with. */
declare language: string | null

/** The current textual contents of this element. */
declare content: string

/** The compiled/highlighted HTML. */
declare html?: string

constructor() {
super()

this.language = null
this.content = ""

// observer for watching for changes to textual content
this.observer = observe(this, () => this.update())
}

/**
* Extracts the language to highlight with from this elements classes.
* Specifically, the `wj-language-{name}` class.
*/
private getLanguageFromClass() {
const classes = Array.from(this.classList)
for (const name of classes) {
// this will always be ASCII lowercased,
// so we can just use a simple check
if (name.startsWith("wj-language-")) return name.substring(12)
}
return null
}

/** Ran whenever highlighting needs to be updated. */
@pauseObservation
private async update() {
// get the element every time we update,
// because it might have been replaced by morphing or something
const element = this.querySelector("code")
if (!element) return

const language = this.getLanguageFromClass()

// jump out early if no language
if (!language) {
// replace old highlighting
if (this.language) {
this.language = null
await animationFrame(() => {
this.content = element.innerText
this.html = this.content
element.innerHTML = this.content
})
}
return
}

await animationFrame(async () => {
const content = element.innerText

// don't waste resources if we're just doing the same thing
if (!this.html || this.content !== content || this.language !== language) {
this.language = language
this.content = content
this.html = await Prism.highlight(content, language!)
}

await animationFrame(() => (element.innerHTML = this.html!))
})
}

// -- LIFECYCLE

connectedCallback() {
this.update()
}
}

/** Button that, when clicked, copies the contents of a `[[code]]` block. */
export class CodeCopyElement extends BaseButton {
static tag = "wj-code-copy"

whenClicked() {
const code = this.closest(".wj-code")?.querySelector("code")
if (!code) return

const text = code.innerText
navigator.clipboard.writeText(text).then(() => {
this.classList.add("wj-code-copy-success")
timeout(1000, () => this.classList.remove("wj-code-copy-success"))
})
}
}

declare global {
interface HTMLElementTagNameMap {
"wj-code": CodeElement
"wj-code-copy": CodeCopyElement
}

interface Window {
CodeElement: typeof CodeElement
CodeCopyElement: typeof CodeCopyElement
}
}

addElement(CodeElement, "CodeElement")
addElement(CodeCopyElement, "CodeCopyElement")
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.wj-collapsible {
display: block;
}

.wj-collapsible-button {
display: inline-block;
list-style: none;
cursor: pointer;
user-select: none;
}

.wj-collapsible[open] {
> .wj-collapsible-button {
display: none;
}

&[data-show-top] > .wj-collapsible-button-top {
display: inline-block;

> .wj-collapsible-show-text {
display: none;
}
}

&[data-show-bottom] > .wj-collapsible-button-bottom {
display: inline-block;
}
}

.wj-collapsible:not([open]) {
> .wj-collapsible-button > .wj-collapsible-hide-text {
display: none;
}
}

.wj-collapsible-content {
> :first-child {
margin-top: 0;
}

> :last-child {
margin-bottom: 0;
}
}
31 changes: 31 additions & 0 deletions modules/ftml-components/src/components/collapsible/collapsible.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { addElement, BaseButton } from "@wikijump/dom"

/**
* Button that shows up at the bottom of a FTML `[[collapsible]]` block.
* Closes the collapsible when clicked.
*/
export class CollapsibleBottomButtonElement extends BaseButton {
static tag = "wj-collapsible-button-bottom"

get details() {
const details = this.closest("details.wj-collapsible")
if (!details) throw new Error("No details found")
return details as HTMLElement
}

whenClicked() {
this.details.removeAttribute("open")
}
}

declare global {
interface HTMLElementTagNameMap {
"wj-collapsible-button-bottom": CollapsibleBottomButtonElement
}

interface Window {
CollapsibleBottomButtonElement: typeof CollapsibleBottomButtonElement
}
}

addElement(CollapsibleBottomButtonElement, "CollapsibleBottomButtonElement")
Loading

0 comments on commit 5293810

Please sign in to comment.