diff --git a/actions/createIdentity.ts b/actions/createIdentity.ts
new file mode 100644
index 00000000..51ec0f7d
--- /dev/null
+++ b/actions/createIdentity.ts
@@ -0,0 +1,48 @@
+import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
+import {
+ entities,
+ permission_tokens,
+ permission_token_rights,
+ entity_sets,
+ facts,
+ identities,
+} from "drizzle/schema";
+import { redirect } from "next/navigation";
+import postgres from "postgres";
+import { v7 } from "uuid";
+import { sql } from "drizzle-orm";
+import { cookies } from "next/headers";
+export async function createIdentity(db: PostgresJsDatabase) {
+ return db.transaction(async (tx) => {
+ // Create a new entity set
+ let [entity_set] = await tx.insert(entity_sets).values({}).returning();
+ // Create a root-entity
+ let [entity] = await tx
+ .insert(entities)
+ // And add it to that permission set
+ .values({ set: entity_set.id, id: v7() })
+ .returning();
+ //Create a new permission token
+ let [permissionToken] = await tx
+ .insert(permission_tokens)
+ .values({ root_entity: entity.id })
+ .returning();
+ //and give it all the permission on that entity set
+ let [rights] = await tx
+ .insert(permission_token_rights)
+ .values({
+ token: permissionToken.id,
+ entity_set: entity_set.id,
+ read: true,
+ write: true,
+ create_token: true,
+ change_entity_set: true,
+ })
+ .returning();
+ let [identity] = await tx
+ .insert(identities)
+ .values({ home_page: permissionToken.id })
+ .returning();
+ return identity;
+ });
+}
diff --git a/actions/createNewDoc.ts b/actions/createNewDoc.ts
new file mode 100644
index 00000000..761528a2
--- /dev/null
+++ b/actions/createNewDoc.ts
@@ -0,0 +1,92 @@
+"use server";
+
+import { drizzle } from "drizzle-orm/postgres-js";
+import {
+ entities,
+ permission_tokens,
+ permission_token_rights,
+ entity_sets,
+ facts,
+ permission_token_on_homepage,
+} from "drizzle/schema";
+import { redirect } from "next/navigation";
+import postgres from "postgres";
+import { v7 } from "uuid";
+import { sql } from "drizzle-orm";
+import { cookies } from "next/headers";
+import { createIdentity } from "./createIdentity";
+const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 });
+const db = drizzle(client);
+
+export async function createNewDoc() {
+ let cookieStore = cookies();
+ let identity = cookieStore.get("identity")?.value;
+ if (!identity) {
+ let newIdentity = await createIdentity(db);
+ cookieStore.set("identity", newIdentity.id, { sameSite: "strict" });
+ identity = newIdentity.id;
+ }
+
+ let { permissionToken } = await db.transaction(async (tx) => {
+ // Create a new entity set
+ let [entity_set] = await tx.insert(entity_sets).values({}).returning();
+ // Create a root-entity
+ let [entity] = await tx
+ .insert(entities)
+ // And add it to that permission set
+ .values({ set: entity_set.id, id: v7() })
+ .returning();
+ //Create a new permission token
+ let [permissionToken] = await tx
+ .insert(permission_tokens)
+ .values({ root_entity: entity.id })
+ .returning();
+ //and give it all the permission on that entity set
+ let [rights] = await tx
+ .insert(permission_token_rights)
+ .values({
+ token: permissionToken.id,
+ entity_set: entity_set.id,
+ read: true,
+ write: true,
+ create_token: true,
+ change_entity_set: true,
+ })
+ .returning();
+
+ // and add it to created_by for the identity
+ await tx
+ .insert(permission_token_on_homepage)
+ .values({ identity, token: permissionToken.id });
+ let [blockEntity] = await tx
+ .insert(entities)
+ // And add it to that permission set
+ .values({ set: entity_set.id, id: v7() })
+ .returning();
+
+ await tx.insert(facts).values([
+ {
+ id: v7(),
+ entity: entity.id,
+ attribute: "card/block",
+ data: sql`${{ type: "ordered-reference", value: blockEntity.id, position: "a0" }}::jsonb`,
+ },
+ {
+ id: v7(),
+ entity: blockEntity.id,
+ attribute: "block/type",
+ data: sql`${{ type: "block-type-union", value: "heading" }}::jsonb`,
+ },
+ {
+ id: v7(),
+ entity: blockEntity.id,
+ attribute: "block/heading-level",
+ data: sql`${{ type: "number", value: 1 }}::jsonb`,
+ },
+ ]);
+
+ return { permissionToken, rights, entity, entity_set };
+ });
+
+ redirect(`/${permissionToken.id}?focusFirstBlock`);
+}
diff --git a/actions/deleteDoc.ts b/actions/deleteDoc.ts
new file mode 100644
index 00000000..b15d65d5
--- /dev/null
+++ b/actions/deleteDoc.ts
@@ -0,0 +1,40 @@
+"use server";
+
+import { drizzle } from "drizzle-orm/postgres-js";
+import {
+ entities,
+ permission_tokens,
+ permission_token_rights,
+} from "drizzle/schema";
+import { redirect } from "next/navigation";
+import postgres from "postgres";
+import { v7 } from "uuid";
+import { eq, sql } from "drizzle-orm";
+import { cookies } from "next/headers";
+import { PermissionToken } from "src/replicache";
+import { revalidatePath } from "next/cache";
+const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 });
+const db = drizzle(client);
+
+export async function deleteDoc(permission_token: PermissionToken) {
+ await db.transaction(async (tx) => {
+ let [token] = await tx
+ .select()
+ .from(permission_tokens)
+ .leftJoin(
+ permission_token_rights,
+ eq(permission_tokens.id, permission_token_rights.token),
+ )
+ .where(eq(permission_tokens.id, permission_token.id));
+
+ console.log(token);
+ if (!token.permission_token_rights?.write) return;
+ await tx
+ .delete(entities)
+ .where(eq(entities.set, token.permission_token_rights.entity_set));
+ await tx
+ .delete(permission_tokens)
+ .where(eq(permission_tokens.id, permission_token.id));
+ });
+ return revalidatePath("/docs");
+}
diff --git a/app/[doc_id]/Doc.tsx b/app/[doc_id]/Doc.tsx
index c1a175d9..eacb865d 100644
--- a/app/[doc_id]/Doc.tsx
+++ b/app/[doc_id]/Doc.tsx
@@ -4,7 +4,10 @@ import { Attributes } from "src/replicache/attributes";
import { createServerClient } from "@supabase/ssr";
import { SelectionManager } from "components/SelectionManager";
import { Cards } from "components/Cards";
-import { ThemeProvider } from "components/ThemeManager/ThemeProvider";
+import {
+ ThemeBackgroundProvider,
+ ThemeProvider,
+} from "components/ThemeManager/ThemeProvider";
import { MobileFooter } from "components/MobileFooter";
import { PopUpProvider } from "components/Toast";
import { YJSFragmentToString } from "components/Blocks/TextBlock/RenderYJSFragment";
@@ -30,15 +33,17 @@ export function Doc(props: {
>
+{/* Render a placeholder if there are no other blocks in the card, else just show the blank line*/} {props.first ? "Title" :diff --git a/components/Buttons.tsx b/components/Buttons.tsx index 943eaf89..08224c26 100644 --- a/components/Buttons.tsx +++ b/components/Buttons.tsx @@ -1,3 +1,5 @@ +import React from "react"; + type ButtonProps = Omit
}; export function ButtonPrimary( props: { @@ -21,3 +23,33 @@ export function ButtonPrimary( ); } + +export const HoverButton = (props: { + icon: React.ReactNode; + label: string; + background: string; + text: string; + backgroundImage?: React.CSSProperties; + noLabelOnMobile?: boolean; +}) => { + return ( + ++ ); +}; diff --git a/components/Cards.tsx b/components/Cards.tsx index bd9947c9..c6085de7 100644 --- a/components/Cards.tsx +++ b/components/Cards.tsx @@ -14,6 +14,7 @@ import { useToaster } from "./Toast"; import { ShareOptions } from "./ShareOptions"; import { MenuItem, Menu } from "./Layout"; import { useEntitySetContext } from "./EntitySetProvider"; +import { HomeButton } from "./HomeButton"; export function Cards(props: { rootCard: string }) { let openCards = useUIState((s) => s.openCards); @@ -34,10 +35,14 @@ export function Cards(props: { rootCard: string }) { e.currentTarget === e.target && blurCard(); }} > -+ {props.icon} +++ {props.label} ++- -diff --git a/components/HomeButton.tsx b/components/HomeButton.tsx new file mode 100644 index 00000000..640e31e3 --- /dev/null +++ b/components/HomeButton.tsx @@ -0,0 +1,20 @@ +import Link from "next/link"; +import { useEntitySetContext } from "./EntitySetProvider"; +import { HomeSmall } from "./Icons"; +import { HoverButton } from "./Buttons"; + +export function HomeButton() { + let entity_set = useEntitySetContext(); + if (!entity_set.permissions.write) return; + return ( + +- + + +++ +
++ + label="Go Home" + background="bg-accent-1" + text="text-accent-2" + /> + + ); +} diff --git a/components/Icons.tsx b/components/Icons.tsx index ffb57575..f106d8dc 100644 --- a/components/Icons.tsx +++ b/components/Icons.tsx @@ -24,6 +24,26 @@ export const HomeMedium = (props: Props) => { // SMALL ICONS 24X24 +export const AddSmall = (props: Props) => { + return ( + + ); +}; + export const BlockSmall = (props: Props) => { return (