-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
70 changed files
with
5,256 additions
and
422 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# ftml-components | ||
|
||
Custom elements and components for FTML. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") |
44 changes: 44 additions & 0 deletions
44
modules/ftml-components/src/components/collapsible/_collapsible.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
31
modules/ftml-components/src/components/collapsible/collapsible.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") |
Oops, something went wrong.