11.2025: new version released, sample folder added

This commit is contained in:
metacryst
2025-11-30 02:50:10 -06:00
parent 6e2b4dcdbd
commit ed6d885557
24 changed files with 2098 additions and 1505 deletions

1
.env Normal file
View File

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

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

@@ -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>

1939
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;