Compare commits

...

10 Commits

Author SHA1 Message Date
metacryst
ed6d885557 11.2025: new version released, sample folder added 2025-11-30 02:50:10 -06:00
metacryst
6e2b4dcdbd extra functions, new test from amplify lessons 2024-09-25 22:03:32 -05:00
metacryst
71b08bd184 Page refers to body, add ZStack, add h1 h2 h3, add positioning validation 2024-09-24 13:08:38 -05:00
metacryst
1060797170 Moving styles, Stacks working in Group 2024-09-12 15:35:13 -05:00
metacryst
cfdf67998d Adding Group 2024-09-12 15:08:51 -05:00
metacryst
9432c65fa4 update readme 2024-09-03 13:17:27 -05:00
metacryst
65f79d1631 moving things, adding a test 2024-05-20 17:26:29 -05:00
metacryst
41ec6b7dd3 ternaries almost done, adding margin function 2024-05-17 12:47:17 -05:00
metacryst
8b2f9e2b77 add vstack children 2024-05-05 15:48:32 -05:00
metacryst
07725994b9 add fontSize custom func 2024-05-05 15:47:38 -05:00
35 changed files with 2472 additions and 1450 deletions

1
.env Normal file
View File

@@ -0,0 +1 @@
VSCE_PAT=9wucEHBNFD5RTS403Oyoflyi984cAwAfa42FHN7tmqmzfbXsSKP9JQQJ99BKACAAAAAAAAAAAAAGAZDO25Ro

View File

@@ -5,25 +5,42 @@
</p>
<br>
Usage: Install the VSCode extension "Quill".
Quill is a SwiftUI-style JavaScript framework. It makes use of components called Shadows, which are HTML Custom Elements.
## Rendering Elements:
### Getting Started:
Go to https://github.com/capturedsun/template-quill and clone this repo.
### App:
src/app.js is the application entry point. Any Shadows rendered inside will be rendered in the body.
### Rendering Elements:
The basis of rendering is the Shadow, which extends HTMLElement. The Shadow is the equivalent of a React Component.
To create a Shadow, simply:
- Create a class which extends Shadow
- Include a render() function
- Register the shadow as an element
...
```
document.body.append(
p("Hi")
.padding("top", 12),
class File extends Shadow {
render = () => {
p(this.name)
p("asd")
}
}
Link({href: "google.com", name: "hey"})
.background("green")
// NavigationBar()
// .onClick()
)
register(File, "file-el")
```
## Needs Support:
Ternaries within render()
Other statements within render()
Multiple-argument attributes in render()
## Limitations:
While rendering is underway, an element's state can only be accessed from within that element
## Boilerplate:
- ```*html```: Type in an HTML file and select the suggestion to create HTML boilerplate.

2
Sample/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
package-lock.json

0
Sample/db/db.json Normal file
View File

18
Sample/package.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "Quill Starter",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node server/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"chalk": "^4.1.2",
"cors": "^2.8.5",
"express": "^4.18.2",
"moment": "^2.30.1"
}
}

12
Sample/server/db/db.js Normal file
View File

@@ -0,0 +1,12 @@
const fs = require('fs/promises');
export default class Database {
constructor() {
}
async saveData() {
}
}

100
Sample/server/index.js Normal file
View File

@@ -0,0 +1,100 @@
const express = require('express');
const cors = require('cors');
const http = require('http');
const chalk = require('chalk');
const moment = require('moment');
const path = require('path');
class Server {
db;
UIPath = path.join(__dirname, '../ui')
registerRoutes(router) {
router.post('/join', this.join)
router.post('/contact', this.contact)
router.get('/*', this.get)
return router
}
join = (req, res) => {
}
contact = (req, res) => {
}
get = async (req, res) => {
console.log(this.UIPath)
let url = req.url
let filePath;
if(url.startsWith("/_")) {
filePath = path.join(this.UIPath, url);
} else if(url.includes("75820185")) {
filePath = path.join(this.UIPath, url.split("75820185")[1]);
} else {
filePath = path.join(this.UIPath, "index.html");
}
res.sendFile(filePath);
}
logRequest(req, res, next) {
const formattedDate = moment().format('M.D');
const formattedTime = moment().format('h:mma');
if(req.url.includes("/api/")) {
console.log(chalk.blue(` ${req.method} ${req.url} | ${formattedDate} ${formattedTime}`));
} else {
if(req.url === "/")
console.log(chalk.gray(` ${req.method} ${req.url} | ${formattedDate} ${formattedTime}`));
}
next();
}
logResponse(req, res, next) {
const originalSend = res.send;
res.send = function (body) {
if(res.statusCode >= 400) {
console.log(chalk.blue( `<-${chalk.red(res.statusCode)}- ${req.method} ${req.url} | ${chalk.red(body)}`));
} else {
console.log(chalk.blue(`<-${res.statusCode}- ${req.method} ${req.url}`));
}
originalSend.call(this, body);
};
next();
}
constructor() {
const app = express();
app.use(cors({ origin: '*' }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(this.logRequest);
app.use(this.logResponse);
let router = express.Router();
this.registerRoutes(router)
app.use('/', router);
const server = http.createServer(app);
const PORT = 3004;
server.listen(PORT, () => {
console.log("\n")
console.log(chalk.yellow("*************** Comal YR ***************"))
console.log(chalk.yellowBright(`Server is running on port ${PORT}: http://localhost`));
console.log(chalk.yellow("***************************************"))
console.log("\n")
});
process.on('SIGINT', async () => {
console.log(chalk.red('Closing server...'));
console.log(chalk.green('Database connection closed.'));
process.exit(0);
});
Object.preventExtensions(this);
}
}
const server = new Server()

1047
Sample/ui/_/code/quill.js Normal file

File diff suppressed because one or more lines are too long

View File

View File

@@ -0,0 +1,7 @@
class Home extends Shadow {
render() {
}
}
register(Home)

13
Sample/ui/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Quill Starter</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="/_/icons/logo.svg">
<link rel="stylesheet" href="/_/code/shared.css">
<script src="/_/code/quill.js"></script>
<script type="module" src="75820185/index.js"></script>
</head>
<body style="margin: 0px">
</body>
</html>

2
Sample/ui/index.js Normal file
View File

@@ -0,0 +1,2 @@
import "./components/Home.js"
Home()

View File

@@ -0,0 +1,38 @@
window.testSuites.push( class testGroup {
BasicDivs() {
let divs = Group(() => {
div()
div()
div()
})
if(!(divs instanceof HTMLElement)) {
return `Did not receive an element!`
}
if(!(divs.children.length === 3)) {
return `Incorrect amount of children!`
}
}
VStack() {
let divs = Group(() => {
VStack(() => {
div()
div()
div()
})
})
if(!(divs instanceof HTMLElement)) {
return `Did not receive an element!`
}
if(!(divs.style.display === "flex")) {
return `Did not receive a flex container!`
}
if(!(divs.children.length === 3)) {
return `Incorrect amount of children!`
}
}
})

View File

@@ -0,0 +1,79 @@
window.testSuites.push( class testStacks {
NestedChildren() {
register(class File extends Shadow {
$name
render = () => {
p(this.name)
VStack(() => {
p("Learn to code inside of a startup")
p("➵")
.position("absolute")
.fontSize(30)
.left("50%")
.top("50%")
.transformOrigin("center")
.transform("translate(-50%, -50%) rotate(90deg)")
.transition("all 1s")
.userSelect("none")
.onAppear((self) => {
setTimeout(() => {
self.style.top = "88%"
}, 100)
})
})
}
constructor() {
super()
}
}, randomName("file"))
const file = File("asdf")
if(file.querySelector(".VStack")?.children.length !== 2) {
return "Incorrect amount of children inside vstack!"
}
}
NestedStacks() {
register(class File extends Shadow {
$name
render = () => {
VStack(() => {
HStack(() => {
p("hi")
})
})
}
}, randomName("file"))
const file = File("asdf")
console.log(file)
let fileStyle = Registry.styles.children[Registry.styles.children.length-1].sheet.cssRules
if(fileStyle[0].cssText.includes("row")) {
return "Should not be horizontal"
}
console.log(file.innerHTML)
if(!file.children[0].matches("div.HStack")) {
return "The child is not an HStack"
}
file.rerender()
if(!file.children[0].matches("div.HStack")) {
return "The child is not an HStack"
}
let fileStyle2 = Registry.styles.children[Registry.styles.children.length-1].sheet.cssRules
if(fileStyle2[0].cssText.includes("row")) {
return "Should not be horizontal"
}
}
})

View File

@@ -1,75 +1,45 @@
window.testSuites.push( class testRender {
window.testSuites.push( class testObservedObject {
SimpleParagraphWithState() {
class File extends Shadow {
$form
render = () => {
p(this.form.data)
}
constructor() {
super()
}
FromJSONFailsWithoutAllFields() {
class Form extends ObservedObject {
id
path
$canvasPosition
}
window.register(File, randomName("file"))
let form = {data: "asdf"}
const el = window.File(form)
try {
let obj = Form.create({id: "123"})
return "Not implemented"
} catch {}
}
if(!(el.firstChild?.matches("p"))) {
return `Child paragraph not rendered`
FromJSONInitsAllFields() {
class Form extends ObservedObject {
id
path
$canvasPosition
}
if(!(el.firstChild.innerText === "asdf")) {
return "Child para does not have inner text"
let obj = Form.create({id: "123", path: "/", canvasPosition: "25|25"})
if(!(obj && obj["id"] === "123" && obj["path"] === "/" && obj["canvasPosition"] === "25|25")) {
return "Not all fields initialized!"
}
}
ParagraphConstructorChangeState() {
register(class File extends Shadow {
$name
DefaultValueWorks() {
class WindowState extends ObservedObject {
$sidebarOut = false
}
render = () => {
p(this.name)
}
constructor() {
super()
}
}, randomName("file"))
let obj = WindowState.create()
console.log(obj)
let name = "asdf"
const file = File(name)
file.name = "hey123"
if(file.firstChild.innerText !== "hey123") {
return "Paragraph did not react to change!"
if(obj.sidebarOut !== false) {
return "Default field not set"
}
}
LiteralDoesNotCreateFalseReactivity() {
register(class File extends Shadow {
$name = "asd"
render = () => {
p(this.name)
p("asd")
}
constructor() {
super()
}
}, randomName("file"))
const file = File()
file.name = "hey123"
if(file.children[1].innerText === "hey123") {
return "Paragraph innertext falsely changed"
}
}
// throw some sort of warning if a global OO is accessed without "this"
DefaultObservedObject() {
window.Form = class Form extends ObservedObject {
@@ -155,5 +125,38 @@ window.testSuites.push( class testRender {
return "No reactivity for adding children"
}
}
NotExtensible() {
return "not done"
}
// MustInitAllFields() {
// class Form extends ObservedObject {
// id
// path
// $canvasPosition
// }
// let obj = Form.create({id: "123", path: "/", canvasPosition: "25|25"})
// if(!(obj && obj["id"] === "123" && obj["path"] === "/" && obj["canvasPosition"] === "25|25")) {
// return "Not all fields initialized!"
// }
// }
// ChangingObjChangesInstance() {
// class Form extends ObservedObject {
// id
// path
// $canvasPosition
// }
// let json = {id: "123", path: "/", canvasPosition: "25|25"}
// let obj = Form.create({id: "123", path: "/", canvasPosition: "25|25"})
// json.id = "456"
// if(!(obj["id"] === "456")) {
// return "Change to original object was not reflected!"
// }
// }
})

View File

@@ -1,13 +1,19 @@
/*
"(" is preceding character: el, el.attr, if, switch
el: the el is window.rendering
el.attr:
find the function and attr in the string
if there are multiple instances of being used with this el, add to a list (and if no list then make it and we are first)
if: the el is window.rendering. rerender el
switch: the el is window.rendering. rerender el
*/
window.testSuites.push(
class ParseRender {
// CopyTo() {
// let str = "render=()=>{VStack(()=>{"
// let ret = str.copyTo("{")
// if(ret !== "render=()=>") return "Copy 1 failed!"
// }
ParseRender() {
class Sidebar extends Shadow {

126
Test/Skeleton/state.test.js Normal file
View File

@@ -0,0 +1,126 @@
window.testSuites.push( class testState {
SimpleParagraphWithState() {
class File extends Shadow {
$form
render = () => {
p(this.form.data)
}
constructor() {
super()
}
}
window.register(File, randomName("file"))
let form = {data: "asdf"}
const el = window.File(form)
if(!(el.firstChild?.matches("p"))) {
return `Child paragraph not rendered`
}
if(!(el.firstChild.innerText === "asdf")) {
return "Child para does not have inner text"
}
}
ParagraphConstructorChangeState() {
register(class File extends Shadow {
$name
render = () => {
p(this.name)
}
constructor() {
super()
}
}, randomName("file"))
let name = "asdf"
const file = File(name)
file.name = "hey123"
if(file.firstChild.innerText !== "hey123") {
return "Paragraph did not react to change!"
}
}
LiteralDoesNotCreateFalseReactivity() {
register(class File extends Shadow {
$name = "asd"
render = () => {
p(this.name)
p("asd")
}
constructor() {
super()
}
}, randomName("file"))
const file = File()
file.name = "hey123"
if(file.children[1].innerText === "hey123") {
return "Paragraph innertext falsely changed"
}
}
/*
State itself should check if the reactivity is based on an element or a standalone expression
If standalone, handle it
If element, push the info for initReactivity to handle it
*/
TernaryInState() {
register(class File extends Shadow {
$name
render = () => {
p(this.name)
.fontSize(this.name === "asdf" ? 16 : 32)
}
constructor() {
super()
}
}, randomName("file"))
let name = "asdf"
const file = File(name)
if(file.style.fontSize !== "16px") {
return "fail"
}
}
StateWorksWithCustomStyleFunctions() {
// reactive setting needs to use the actual style functions
register(class File extends Shadow {
$paraWidth = 16
render = () => {
p("guppy")
.width(this.paraWidth)
}
constructor() {
super()
}
}, randomName("file"))
const file = File()
file.paraWidth = 18
if(file.firstChild.style.width !== "18px") {
return "Width did not reactively change!"
}
}
})

View File

@@ -1,77 +0,0 @@
window.testSuites.push( class testObservedObject {
FromJSONFailsWithoutAllFields() {
class Form extends ObservedObject {
id
path
$canvasPosition
}
try {
let obj = Form.create({id: "123"})
return "Not implemented"
} catch {}
}
FromJSONInitsAllFields() {
class Form extends ObservedObject {
id
path
$canvasPosition
}
let obj = Form.create({id: "123", path: "/", canvasPosition: "25|25"})
if(!(obj && obj["id"] === "123" && obj["path"] === "/" && obj["canvasPosition"] === "25|25")) {
return "Not all fields initialized!"
}
}
DefaultValueWorks() {
class WindowState extends ObservedObject {
$sidebarOut = false
}
let obj = WindowState.create()
console.log(obj)
if(obj.sidebarOut !== false) {
return "Default field not set"
}
}
// throw some sort of warning if a global OO is accessed without "this"
NotExtensible() {
return "not done"
}
// MustInitAllFields() {
// class Form extends ObservedObject {
// id
// path
// $canvasPosition
// }
// let obj = Form.create({id: "123", path: "/", canvasPosition: "25|25"})
// if(!(obj && obj["id"] === "123" && obj["path"] === "/" && obj["canvasPosition"] === "25|25")) {
// return "Not all fields initialized!"
// }
// }
// ChangingObjChangesInstance() {
// class Form extends ObservedObject {
// id
// path
// $canvasPosition
// }
// let json = {id: "123", path: "/", canvasPosition: "25|25"}
// let obj = Form.create({id: "123", path: "/", canvasPosition: "25|25"})
// json.id = "456"
// if(!(obj["id"] === "456")) {
// return "Change to original object was not reflected!"
// }
// }
})

View File

@@ -1,11 +1,13 @@
console.log("Tests initializing.")
window.testSuites = [];
await import ("./parse.test.js")
await import ("./init.test.js")
await import ("./render.test.js")
await import ("./observedobject.test.js")
await import ("./parserender.test.js")
await import ("./Skeleton/parse.test.js")
await import ("./Skeleton/init.test.js")
await import ("./Skeleton/observedobject.test.js")
await import ("./Skeleton/parserender.test.js")
await import ("./Skeleton/state.test.js")
await import ("./Element/stacks.test.js")
await import ("./Element/Group.test.js")
window.randomName = function randomName(prefix) {
const sanitizedPrefix = prefix.toLowerCase().replace(/[^a-z0-9]/g, '');

View File

@@ -5,7 +5,7 @@ Forked from this repository:
## Boilerplate:
- ```*html```: Type in an HTML file and select the suggestion to create HTML boilerplate.
- ```*element```: Type in a JS file and select the suggestion to create JS Custom Element boilerplate.
- ```*shadow```: Type in a JS file and select the suggestion to create JS Custom Element boilerplate.
## Functions:
Clone this repository into the top level of the project you are working on, so the HTML can find the "quill.js" functions.

15
VSCode/deploy-howto.md Normal file
View File

@@ -0,0 +1,15 @@
# To Deploy Extension
```vsce package```
```vsce publish```
# To Get PAT
Login to Azure
Search "Devops"
Login to devops (samuel@sun.museum)
Click "User Settings" in the top right > "Personal Access Tokens"
Create one which has "Allow all Organizations" and "Marketplace" > "Manage" selected
Put it in the .env file here
set it in the terminal like `export VSCE_PAT="<token>"`

View File

@@ -2,7 +2,7 @@
"name": "quill",
"displayName": "Quill",
"description": "HTML/CSS Syntax highlighting, best used with the Quill framework",
"version": "1.0.4",
"version": "1.0.6",
"publisher": "capturedsun",
"icon": "docs/Quill.png",
"engines": {

BIN
VSCode/quill-1.0.5.vsix Normal file

Binary file not shown.

View File

@@ -2,46 +2,17 @@
"*page": {
"prefix": "*html",
"body": [
"<!DOCTYPE html>",
"<!DOCTYPE html>",
"<html lang=\"en\">",
" <head>",
" <title>Quill</title>",
" <link rel=\"icon\" href=\"\">",
" <link rel=\"stylesheet\" href=\"\">",
" <script type=\"module\">",
" window.addStyle = function addStyle(cssString) {",
" let container = document.querySelector(\"style#quillStyles\");",
" if(!container) {",
" container = document.createElement('style');",
" container.id = \"quillStyles\";",
" document.head.appendChild(container);",
" }",
"",
" let primarySelector = cssString.substring(0, cssString.indexOf(\"{\"));",
" primarySelector = primarySelector.replace(/\\*/g, \"all\");",
" primarySelector = primarySelector.replace(/#/g, \"id-\");",
" primarySelector = primarySelector.replace(/,/g, \"\");",
" let stylesheet = container.querySelector(`:scope > style[id='${primarySelector}']`)",
" if(!stylesheet) {",
" stylesheet = document.createElement('style');",
" stylesheet.id = primarySelector;",
" stylesheet.appendChild(document.createTextNode(cssString));",
" container.appendChild(stylesheet);",
" } else {",
" stylesheet.innerText = cssString",
" }",
" }",
"",
" window.html = function html(elementString) {",
" let parser = new DOMParser();",
" let doc = parser.parseFromString(elementString, 'text/html');",
" return doc.body.firstChild;",
" }",
" </script>",
" <script type=\"module\" src=\"\"></script>",
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">",
" <link rel=\"icon\" href=\"/_/icons/logo.svg\">",
" <link rel=\"stylesheet\" href=\"/_/code/shared.css\">",
" <script src=\"/_/code/quill.js\"></script>",
" <script type=\"module\" src=\"75820185/index.js\"></script>",
" </head>",
" <body>",
"",
" <body style=\"margin: 0px\">",
" </body>",
"</html>"
],

View File

@@ -2,7 +2,7 @@
"html": {
"prefix": "html",
"body": [
"html(`$1`);"
"html(`$`);"
],
"description": "Create a DOM node"
},
@@ -15,35 +15,17 @@
"description": "Use the DOM collection of functions"
},
"*element": {
"prefix": "*element",
"*shadow": {
"prefix": "*shadow",
"body": [
"class Index extends HTMLElement {",
"",
" css = /*css*/ `",
" index-el {",
" ",
" }",
" `",
"",
" html = /*html*/ `",
" `",
"",
" constructor() {",
" super();",
" addStyle(this.css);",
" this.innerHTML = this.html;",
" }",
"",
" connectedCallback() {",
"class Index extends Shadow {",
" render() {",
" ",
" }",
"",
"}",
"",
"customElements.define('index-el', Index);",
"export default Index;"
" ",
"register(Index)"
],
"description": "Custom Element Template"
"description": "Custom Shadow Template"
}
}

View File

@@ -1,26 +0,0 @@
Attribute/State Cases:
Dual Instantiation
- HTML-first instantiation from attributes (when first loaded and parsed)
observedAttributes will pick this up
- JS-first instantiation where attributes are set from constructor (or) from init function (or)
press puts attributes on from state before saving
init function can set attributes and variables - perhaps state is always required to be passed in
Usage Flexibility
- attributes can have default values
$url = "hey"
- attributes can be named or unnamed when passed in to constructor functions
Attribute / State Reflexivity
- when attribute is changed, state value is changed
modify prototype at runtime? Add overrides for setattr and remove? ||
use observedAttributes + attributeChanged (not good) - Forms parent element?
- when state is changed, attribute value is changed
modify prototype at runtime to add a setter for the state such that when it is set it sets the attribute
Bindings
- should be able to have a child variable be bound to that of a parent
Binding is denoted by prior to variable
State is denoted by "$" prior to variable

13
app.js
View File

@@ -1,13 +0,0 @@
/*
Captured Sun
*/
"use strict";
class Home extends Page {
render = () => {
("hello world")
}
}
export default Home

View File

@@ -1,5 +0,0 @@
# To Deploy Extension
```vsce package```
```vsce publish```

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Quill</title>
<link rel="icon" href="">
<link rel="stylesheet" href="">
<script src=""></script>
<script src="Quill/index.js"></script>
<script type="module">
import Home from "./app.js"
window.routes = {
"/": Home
}
</script>
</head>
<body>
</body>
</html>

1748
index.js

File diff suppressed because one or more lines are too long

151
notes.txt
View File

@@ -1,151 +0,0 @@
Shadow.File = (param) => new class {
trippy = "asd"
constructor() {
console.log(param)
}
}
console.log(Shadow.File("as"))
ObservedObject.WindowState = () => ({
sidebarOut: false,
children: null
})
let windowState = ObservedObject.WindowState()
console.log(windowState)
Shadow(class File {
}, "file-")
3/16
const TestClass = () => new class {
constructor() {
console.log("hey")
}
}()
This works. Could extend shadow. This way the function and the actual code are not separate.
3/10
Ran into a problem where I can't call the same element within itself.
There are two problems:
1. Javascript scoping means that it tries to call the class it is inside of.
2. Quill instantiates the object when registered, to track its state
This is what I ended up going with - simply not using the Space() recursively and instead making a child space.
class Space extends HTMLElement {
form = Forms.observe(window.location.pathname, this)
contents = [
...this.form.children.map(form => {
switch(form.type) {
case "file":
return File()
case "space":
return ChildSpace()
case "link":
return Link()
}
})
]
constructor() {
super()
console.log(this.form.path)
console.log(this.contents)
this.render(...this.contents)
}
}
This was my attempt to see if an anonymous class can be used. The class functions and extends HTMLElement - so problem #2 is solved.
Problem #1 however, scoping, is not solved unless putting "window.Space()" instead of Space() here, so that it does not
attempt to access the named function value. It seems both functions and classes have this problem. Perhaps there is a
different way it could be done in Quill, like so -
const el = () => class extends HTMLElement {
...
}
quill.register(el, "Space", "parchment-space")
However, not naming it at the top is less than desirable.
quill("Space", class extends HTMLElement {
form = Forms.observe(window.location.pathname, this)
contents = [
...this.form.children.map(form => {
switch(form.type) {
case "file":
return File()
case "space":
return ChildSpace()
case "link":
return Link()
}
})
]
constructor() {
super()
console.log(this.form.path)
console.log(this.contents)
this.render(...this.contents)
}
})
this would probably work. Still less than ideal but maybe if we used syntax highlighting it could be alright.
How to name something without the class having access? This is the problem. I didn't try it without being an arrow function so
perhaps this would have a chance.
// const Space = () => class extends HTMLElement {
// form = Forms.observe(window.location.pathname, this)
// contents = [
// ...this.form.children.map(form => {
// switch(form.type) {
// case "file":
// return File()
// case "space":
// return Space()
// case "link":
// return Link()
// }
// })
// ]
// constructor() {
// super()
// console.log(this.form.path)
// console.log(this.contents)
// this.render(...this.contents)
// }
// }
// let instan = Space()
// customElements.define("space-", instan)
// window.Space = () => "boi"
// console.log(new instan())
window.register(Space, "parchment-space")

151
path.js
View File

@@ -1,151 +0,0 @@
class PathProcessor {
path;
hasTrailingSlash = false;
node = (typeof module !== 'undefined' && module.exports) ? true : false;
constructor(path) {
this.path = path;
if(path === undefined) {
this.path = ""
}
}
#removeTrailingSlash(path) {
if(path === "/") {
return path;
}
return path.endsWith("/") ? path.slice(0, -1) : path
}
full() {
if(!this.node) return;
let path = this.path;
this.path = ""
this.join(Path.homedir(), path)
return this;
}
web() {
if(!this.node) return;
const os = require('os')
this.path = this.path.replace(this.#removeTrailingSlash(os.homedir()), "")
if(this.path === "") {
this.path = "/"
}
return this;
}
encode() { // Uses the built in encodeURI and also encodes certain characters that are't covered by it
this.path = encodeURI(this.path).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);
});
return this;
}
decoded() {
this.path = decodeURIComponent(this.path);
return this;
}
parent() {
const parts = this.path.split('/').filter(Boolean);
parts.pop();
this.path = '/' + parts.join('/');
return this;
}
end() {
const parts = this.path.split('/').filter(Boolean);
this.path = parts.pop() || '';
return this;
}
trailingSlash() {
this.path = this.path.endsWith("/") ? this.path : this.path+"/";
this.hasTrailingSlash = true;
return this;
}
noTrailingSlash() {
this.path = this.#removeTrailingSlash(this.path)
return this;
}
join(...segments) {
if (this.path) {
segments.unshift(this.path);
}
this.path = segments
.map((part, index) => {
if (index === 0) {
return part.trim().replace(/[/]*$/g, '');
} else {
return part.trim().replace(/(^[/]*|[/]*$)/g, '');
}
})
.filter(Boolean) // Remove empty segments
.join('/');
return this;
}
components() {
return this.path.split('/').filter(Boolean);
}
build() {
return this.hasTrailingSlash ? this.path : this.#removeTrailingSlash(this.path)
}
}
export default class Path {
static full(path) {
return new PathProcessor(path).full();
}
static web(path) {
return new PathProcessor(path).web();
}
static decoded(path) {
return new PathProcessor(path).decoded()
}
static encode(path) {
return new PathProcessor(path).encode()
}
static parent(path) {
return new PathProcessor(path).parent();
}
static end(path) {
return new PathProcessor(path).end();
}
static trailingSlash(path) {
return new PathProcessor(path).trailingSlash();
}
static noTrailingSlash(path) {
return new PathProcessor(path).noTrailingSlash();
}
static components(path) {
return new PathProcessor(path).components();
}
static join(...segments) {
return new PathProcessor(null).join(...segments);
}
static homedir() {
if(typeof module === 'undefined' || !module.exports) return;
const os = require('os')
let ret = os.homedir().replace(/\\/g, '/').replace(/^[a-zA-Z]:/, '');
return ret
}
}
window.Path = Path;