Compare commits

...

2 commits

Author SHA1 Message Date
Anish Lakhwara 1a8ebaf88d feat: selectbox action component 2025-02-19 11:09:54 -08:00
Anish Lakhwara d5791bf5ed revert: broken build 2025-02-19 11:09:45 -08:00
3 changed files with 66 additions and 87 deletions

View file

@ -214,7 +214,7 @@ function App({ ctx }) {
<>
<section className="pt-8 container">
<Input type="text"
className="bg-background p-4"
className="bg-background"
placeholder="..."
value={newText}
onKeyUp={parseTodos}

View file

@ -7,16 +7,53 @@ export interface InputProps
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
const [selectedIndex, setSelectedIndex] = React.useState(0)
const options = ["add", "done", "delete"]
const handleWheel = (event: React.WheelEvent) => {
event.preventDefault()
if (event.deltaY > 0) {
// Scroll down
setSelectedIndex((prev) => (prev + 1) % options.length)
} else {
// Scroll up
setSelectedIndex((prev) => (prev - 1 + options.length) % options.length)
}
}
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
ref={ref}
{...props}
/>
<div className="relative"
onWheel={handleWheel}
>
<select
className={cn(
"absolute top-0 left-0 h-9 rounded-l-md border-r border-input bg-transparent px-2 text-sm cursor-default",
"shadow-sm transition-all duration-200 text-center appearance-none",
)}
value={options[selectedIndex]}
onChange={(e) => {
setSelectedIndex(options.indexOf(e.target.value))
}}
>
<option value="" disabled selected>
Actions
</option>
{options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-background px-[90px] text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
ref={ref}
{...props}
/>
</div>
)
}
)

View file

@ -1,90 +1,31 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from "./App.tsx";
import Root from "./Root.tsx";
import { start } from "@vlcn.io/ws-client/worker.js";
import { createDbProvider } from "@vlcn.io/ws-browserdb";
import initWasm from '@vlcn.io/crsqlite-wasm';
import wasmUrl from '@vlcn.io/crsqlite-wasm/crsqlite.wasm?url';
import tblrx from '@vlcn.io/rx-tbl';
async function initializeDatabase() {
const sqlite = await initWasm(() => wasmUrl);
const db = await sqlite.open("todo.db");
await db.exec(`
CREATE TABLE IF NOT EXISTS todos (
id BLOB PRIMARY KEY NOT NULL,
description TEXT,
project text,
tags text,
due text,
wait text,
priority text,
urgency real,
completed INTEGER NOT NULL DEFAULT 0
);
SELECT crsql_as_crr('todos');
`);
db.onUpdate(async () => {
const changes = await db.execA(`SELECT * FROM crsql_changes WHERE db_version > 0 AND site_id = crsql_site_id()`);
const sqlite = await initWasm(() => wasmUrl);
sendChangesToServer(changes);
});
return db;
}
const db = await sqlite.open("todo.db");
await db.exec(`
CREATE TABLE IF NOT EXISTS todos (
id BLOB PRIMARY KEY NOT NULL,
description TEXT,
project text,
tags text,
due text,
wait text,
priority text,
urgency real,
completed INTEGER NOT NULL DEFAULT 0
);
SELECT crsql_as_crr('todos');
`);
const config = {
dbProvider: createDbProvider(),
transportProvider: (dbName) => new WebSocket(`ws://localhost:8080/sync/${dbName}`),
};
start(config);
const ws = new WebSocket('ws://localhost:8080/sync');
ws.onmessage = async function(event) {
const { type, data } = JSON.parse(event.data);
if (type === 'changes') {
await applyChanges(data);
}
};
function sendChangesToServer(changes) {
const formattedChanges = changes.map(change => ({
TableName: change[0],
PK: Array.isArray(change[1]) ? btoa(String.fromCharCode.apply(null, change[1])) : btoa(change[1]),
ColumnName: change[2],
Value: Array.isArray(change[3]) ? btoa(String.fromCharCode.apply(null, change[3])) : change[3],
ColVersion: Number(change[4]),
DBVersion: Number(change[5]),
SiteID: Array.isArray(change[6]) ? btoa(new TextDecoder('utf8').decode(change[6])) : btoa(change[6]),
CL: Number(change[7]),
Seq: Number(change[8])
}));
console.log(formattedChanges)
const message = {
type: "changes",
data: formattedChanges
};
ws.send(JSON.stringify(message));
}
async function applyChanges(changes) {
const db = initializeDatabase();
const rx = tblrx(db);
const ctx = { db, rx };
await db.tx(async (tx) => {
for (const change of changes) {
await tx.exec(
`INSERT INTO crsql_changes VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
change
);
}
});
}
const rx = tblrx(db);
const ctx = { db, rx };
document.getElementById("root")!.classList.add("dark");
@ -93,3 +34,4 @@ createRoot(document.getElementById("root") as HTMLElement).render(
<App ctx={ctx} />
</main>
);