mirror of
https://github.com/kou029w/quot.git
synced 2025-03-10 08:25:19 +00:00
Compare commits
No commits in common. "86afc69f5665e4a537c11f9c1b51933f56a07113" and "cd012683057af51529e2a8d8d2b1b00f0a814d65" have entirely different histories.
86afc69f56
...
cd01268305
7 changed files with 36 additions and 122 deletions
|
@ -1,7 +1,7 @@
|
||||||
header {
|
header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly
|
||||||
}
|
}
|
||||||
|
|
||||||
a[href^="/"] {
|
a[href^="/"] {
|
||||||
|
|
|
@ -1,21 +1,14 @@
|
||||||
import type Pages from "../protocol/pages";
|
|
||||||
import "./editor.css";
|
import "./editor.css";
|
||||||
|
|
||||||
export default (props: {
|
export default () => (
|
||||||
id: number;
|
<textarea
|
||||||
onUpdatePage: (content: Pages.RequestContentPage) => void;
|
class="editor"
|
||||||
}) => {
|
autofocus
|
||||||
return (
|
onInput={(e) => {
|
||||||
<textarea
|
e.currentTarget.setAttribute(
|
||||||
id={String(props.id)}
|
"rows",
|
||||||
class="editor"
|
String(Math.max(2, e.currentTarget.value.split("\n").length))
|
||||||
autofocus
|
);
|
||||||
onInput={(e) => {
|
}}
|
||||||
const text = e.currentTarget.value;
|
></textarea>
|
||||||
const lines = text.split("\n");
|
);
|
||||||
props.onUpdatePage({ id: props.id, title: lines[0] ?? "", text });
|
|
||||||
e.currentTarget.setAttribute("rows", String(Math.max(2, lines.length)));
|
|
||||||
}}
|
|
||||||
></textarea>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
function beforeunload() {
|
|
||||||
function listener(e: BeforeUnloadEvent) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.returnValue = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function block() {
|
|
||||||
window.addEventListener("beforeunload", listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unblock() {
|
|
||||||
window.removeEventListener("beforeunload", listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { block, unblock };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default beforeunload;
|
|
|
@ -1,21 +0,0 @@
|
||||||
function throttle<Fn extends (...args: any[]) => any>(
|
|
||||||
fn: Fn,
|
|
||||||
ms: number
|
|
||||||
): (...args: Parameters<Fn>) => void {
|
|
||||||
let throttledFn = () => undefined;
|
|
||||||
let throttled: boolean = false;
|
|
||||||
|
|
||||||
return (...args: Parameters<Fn>): void => {
|
|
||||||
throttledFn = () => fn(...args);
|
|
||||||
if (throttled) return;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
throttledFn();
|
|
||||||
throttled = false;
|
|
||||||
}, ms);
|
|
||||||
|
|
||||||
throttled = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default throttle;
|
|
|
@ -1,12 +1,19 @@
|
||||||
import { createResource } from "solid-js";
|
import { createResource } from "solid-js";
|
||||||
import type Pages from "../protocol/pages";
|
|
||||||
|
|
||||||
async function fetchPages(): Promise<Pages.Response> {
|
type PagesResponse = Array<{
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
created: string;
|
||||||
|
updated: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
async function fetchPages(): Promise<PagesResponse> {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
new URL("/pages?order=updated.desc", import.meta.env.QUOT_API_URL)
|
new URL("/pages?order=updated.desc", import.meta.env.QUOT_API_URL)
|
||||||
);
|
);
|
||||||
const data = (await res.json()) as Pages.Response;
|
const data = await res.json();
|
||||||
return data;
|
return data as PagesResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
|
|
@ -1,55 +1,28 @@
|
||||||
import { createResource } from "solid-js";
|
import { createResource } from "solid-js";
|
||||||
import type Pages from "../protocol/pages";
|
|
||||||
import Editor from "../components/editor";
|
import Editor from "../components/editor";
|
||||||
import beforeunload from "../helpers/beforeunload";
|
|
||||||
import throttle from "../helpers/throttle";
|
|
||||||
|
|
||||||
const intervalMs = 333;
|
type PageResponse = {
|
||||||
const { block, unblock } = beforeunload();
|
id: number;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
created: string;
|
||||||
|
updated: string;
|
||||||
|
};
|
||||||
|
|
||||||
async function updatePage(
|
async function fetchPage(id: number): Promise<PageResponse> {
|
||||||
id: number,
|
|
||||||
content: Pages.RequestContentPage
|
|
||||||
): Promise<boolean> {
|
|
||||||
const res = await fetch(
|
|
||||||
new URL(`/pages?id=eq.${id}`, import.meta.env.QUOT_API_URL),
|
|
||||||
{
|
|
||||||
method: "PUT",
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
body: JSON.stringify(content),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return res.ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchPage(id: number): Promise<Pages.RequestContentPage> {
|
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
new URL(`/pages?id=eq.${id}`, import.meta.env.QUOT_API_URL)
|
new URL(`/pages?id=eq.${id}`, import.meta.env.QUOT_API_URL)
|
||||||
);
|
);
|
||||||
const data = (await res.json()) as Pages.Response;
|
const [data] = await res.json();
|
||||||
return data[0]!;
|
return data as PageResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (props: { id: number }) => {
|
export default (props: { id: number }) => {
|
||||||
const [page, { refetch }] = createResource(props.id, fetchPage);
|
const [page] = createResource(props.id, fetchPage);
|
||||||
const throttledUpdate = throttle(
|
|
||||||
async (id: number, content: Pages.RequestContentPage) => {
|
|
||||||
if (await updatePage(id, content)) {
|
|
||||||
unblock();
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
intervalMs
|
|
||||||
);
|
|
||||||
|
|
||||||
function onUpdatePage(content: Pages.RequestContentPage) {
|
|
||||||
block();
|
|
||||||
throttledUpdate(props.id, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Editor id={props.id} onUpdatePage={onUpdatePage} />
|
<Editor />
|
||||||
<pre>{() => JSON.stringify(page(), null, " ")}</pre>
|
<pre>{() => JSON.stringify(page(), null, " ")}</pre>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
namespace Pages {
|
|
||||||
export type RequestContentPage = {
|
|
||||||
id?: number;
|
|
||||||
title: string;
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ResponsePage = {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
text: string;
|
|
||||||
created: string;
|
|
||||||
updated: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type RequestContent = Array<RequestContentPage>;
|
|
||||||
export type Response = Array<ResponsePage>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Pages;
|
|
Loading…
Add table
Reference in a new issue