remove chains of thought
This commit is contained in:
parent
64de5d735f
commit
ae2624b7c5
|
|
@ -1,52 +0,0 @@
|
||||||
{
|
|
||||||
"thoughts": [
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"text": "Blindfold chess requires internalizing chess structures.",
|
|
||||||
"x": 392,
|
|
||||||
"y": 157
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2",
|
|
||||||
"text": "Internalizing chess structures builds intuition.",
|
|
||||||
"x": 73,
|
|
||||||
"y": 88
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "3",
|
|
||||||
"text": "Blindfold chess improves intuition.",
|
|
||||||
"x": 158,
|
|
||||||
"y": 337
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "4",
|
|
||||||
"text": "Building intuition is essential for chess improvement.",
|
|
||||||
"x": 457,
|
|
||||||
"y": 532
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "5",
|
|
||||||
"text": "Blindfold chess is useful for chess improvement.",
|
|
||||||
"x": 206,
|
|
||||||
"y": 621
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"connections": [
|
|
||||||
{
|
|
||||||
"sourceId": "1",
|
|
||||||
"targetId": "3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sourceId": "2",
|
|
||||||
"targetId": "3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sourceId": "3",
|
|
||||||
"targetId": "5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sourceId": "4",
|
|
||||||
"targetId": "5"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Chains of Thought</title>
|
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
background: white;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
border: solid 1px black;
|
|
||||||
color: black;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: black;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
folk-shape {
|
|
||||||
border-radius: 7px;
|
|
||||||
|
|
||||||
&::part(rotate),
|
|
||||||
&::part(resize-top-left),
|
|
||||||
&::part(resize-top-right),
|
|
||||||
&::part(resize-bottom-right),
|
|
||||||
&::part(resize-bottom-left) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
fc-thought {
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: solid 1px light-dark(rgb(118, 118, 118), rgb(133, 133, 133));
|
|
||||||
display: block;
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
width: 30ch;
|
|
||||||
|
|
||||||
> [name='text'] {
|
|
||||||
padding: 0.5em 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
> button[name='delete'] {
|
|
||||||
font-size: 2rem;
|
|
||||||
line-height: 0.6;
|
|
||||||
padding: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 0%;
|
|
||||||
left: 100%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<button name="open">Open</button>
|
|
||||||
<button name="save">Save</button>
|
|
||||||
<button name="save-as">Save As</button>
|
|
||||||
<main></main>
|
|
||||||
<script type="module" src="./main.ts"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,156 +0,0 @@
|
||||||
import { FolkShape } from '../../../labs/folk-shape.ts';
|
|
||||||
import { FolkArrow } from '../../../labs/folk-arrow.ts';
|
|
||||||
import { FileSaver } from '../src/file-system.ts';
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
'fc-thought': FolkThought;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FolkThought extends HTMLElement {
|
|
||||||
static tagName = 'fc-thought';
|
|
||||||
|
|
||||||
static define() {
|
|
||||||
if (customElements.get(this.tagName)) return;
|
|
||||||
customElements.define(this.tagName, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#deleteButton = this.querySelector('button[name="delete"]') as HTMLButtonElement;
|
|
||||||
#text = this.querySelector('[name="text"]') as HTMLElement;
|
|
||||||
|
|
||||||
#geometry = this.parentElement as FolkShape;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.addEventListener('click', this);
|
|
||||||
}
|
|
||||||
|
|
||||||
get text() {
|
|
||||||
return this.#text.innerHTML;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEvent(event: PointerEvent): void {
|
|
||||||
if (event.type === 'click' && event.target === this.#deleteButton) {
|
|
||||||
this.#geometry.remove();
|
|
||||||
|
|
||||||
document
|
|
||||||
.querySelectorAll(
|
|
||||||
`folk-arrow[source="folk-shape[id='${this.#geometry.id}']"],
|
|
||||||
folk-arrow[target="folk-shape[id='${this.#geometry.id}']"]`
|
|
||||||
)
|
|
||||||
.forEach((el) => el.remove());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FolkShape.define();
|
|
||||||
FolkThought.define();
|
|
||||||
FolkArrow.define();
|
|
||||||
|
|
||||||
interface Thought {
|
|
||||||
id: string;
|
|
||||||
text: string;
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Connection {
|
|
||||||
sourceId: string;
|
|
||||||
targetId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ChainOfThought {
|
|
||||||
thoughts: Thought[];
|
|
||||||
connections: Connection[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const html = String.raw;
|
|
||||||
|
|
||||||
function parseHTML(html: string): Element {
|
|
||||||
return document.createRange().createContextualFragment(html).firstElementChild!;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderThought({ id, x, y, text }: Thought) {
|
|
||||||
return html`<folk-shape id="${id}" x="${x}" y="${y}">
|
|
||||||
<fc-thought>
|
|
||||||
<div contenteditable="true" name="text">${text}</div>
|
|
||||||
<button name="delete">␡</button>
|
|
||||||
</fc-thought>
|
|
||||||
</folk-shape>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderConnection({ sourceId, targetId }: Connection) {
|
|
||||||
return html`<folk-arrow source="folk-shape[id='${sourceId}']" target="folk-shape[id='${targetId}']"></folk-arrow>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderChainOfThought({ thoughts, connections }: ChainOfThought) {
|
|
||||||
return html`${thoughts.map(renderThought).join('')}${connections.map(renderConnection).join('')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseChainOfThought(): ChainOfThought {
|
|
||||||
return {
|
|
||||||
thoughts: Array.from(document.querySelectorAll('folk-shape')).map((el) => ({
|
|
||||||
id: el.id,
|
|
||||||
text: (el.firstElementChild as FolkThought).text,
|
|
||||||
x: el.x,
|
|
||||||
y: el.y,
|
|
||||||
})),
|
|
||||||
connections: Array.from(document.querySelectorAll('folk-arrow')).map((el) => ({
|
|
||||||
sourceId: (el.sourceElement as FolkShape).id,
|
|
||||||
targetId: (el.targetElement as FolkShape).id,
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const openButton = document.querySelector('button[name="open"]')!;
|
|
||||||
const saveButton = document.querySelector('button[name="save"]')!;
|
|
||||||
const saveAsButton = document.querySelector('button[name="save-as"]')!;
|
|
||||||
const main = document.querySelector('main')!;
|
|
||||||
const fileSaver = new FileSaver('chains-of-thought', 'json', 'application/json');
|
|
||||||
|
|
||||||
main.addEventListener('dblclick', (e) => {
|
|
||||||
if (e.target === main) {
|
|
||||||
main.appendChild(
|
|
||||||
parseHTML(
|
|
||||||
renderThought({
|
|
||||||
id: String(document.querySelectorAll('fc-thought').length + 1),
|
|
||||||
text: '',
|
|
||||||
x: e.clientX,
|
|
||||||
y: e.clientY,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
async function openFile(showPicker = true) {
|
|
||||||
try {
|
|
||||||
const text = await fileSaver.open(showPicker);
|
|
||||||
const json = JSON.parse(text || '{ "thoughts": [], "connections": [] }');
|
|
||||||
main.setHTMLUnsafe(renderChainOfThought(json));
|
|
||||||
} catch (e) {
|
|
||||||
// No file handler was persisted or the file is invalid JSON.
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveFile(promptNewFile = false) {
|
|
||||||
const file = JSON.stringify(parseChainOfThought(), null, 2);
|
|
||||||
fileSaver.save(file, promptNewFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
openButton.addEventListener('click', () => {
|
|
||||||
openFile();
|
|
||||||
});
|
|
||||||
|
|
||||||
saveButton.addEventListener('click', () => {
|
|
||||||
saveFile();
|
|
||||||
});
|
|
||||||
|
|
||||||
saveAsButton.addEventListener('click', () => {
|
|
||||||
saveFile(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
openFile(false);
|
|
||||||
Loading…
Reference in New Issue