remove chains of thought

This commit is contained in:
“chrisshank” 2025-01-02 12:33:35 -08:00
parent 64de5d735f
commit ae2624b7c5
3 changed files with 0 additions and 293 deletions

View File

@ -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"
}
]
}

View File

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

View File

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