Compare commits

..

No commits in common. "b9b744e97fb23d0ca52e8bc0ddaced69373a08d4" and "0f100bba3d30cd463fe3da598193ac88e12bbbc7" have entirely different histories.

14 changed files with 156 additions and 514 deletions

View File

@ -1,21 +1,16 @@
"use client"; "use client";
import { useToast } from "@/components/toast";
import { TTCMD } from "@/components/ttcmd"; import { TTCMD } from "@/components/ttcmd";
import { useEffect } from "react";
import { FC, use } from "react"; import { FC, use } from "react";
export const HomeClient: FC<{ body: Promise<string> }> = ({ body }) => { export const HomeClient: FC<{ body: Promise<string> }> = ({ body }) => {
const text = use(body); const text = use(body);
const { createToast } = useToast(); return (
useEffect(() => { <TTCMD
createToast({ body={text}
fading: false, parserId="home"
msg: "TEST TOAST", title="home"
type: "error", />
}); );
}, [createToast]);
return <TTCMD body={text} parserId="home" title="home" />;
}; };

View File

@ -93,12 +93,6 @@
} }
} }
@layer utilities {
.fade-toast {
animation: fadeOut 300ms forwards;
}
}
@keyframes identifier { @keyframes identifier {
} }
@ -108,12 +102,3 @@
list-style: square; list-style: square;
} }
} }
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}

View File

@ -11,8 +11,6 @@ import {
import Link from "next/link"; import Link from "next/link";
import { DevToolboxContextProvider } from "@/components/devtools/context"; import { DevToolboxContextProvider } from "@/components/devtools/context";
import { RecoilRootClient } from "@/components/recoilRoot"; import { RecoilRootClient } from "@/components/recoilRoot";
import { JotaiProvider } from "@/components/jotaiProvider";
import { Toaster } from "@/components/toast";
const roboto = Roboto({ subsets: ["latin"], weight: "400" }); const roboto = Roboto({ subsets: ["latin"], weight: "400" });
@ -76,14 +74,13 @@ export default function RootLayout({
</ul> </ul>
</nav> </nav>
<RecoilRootClient> <RecoilRootClient>
<JotaiProvider>
<DevToolboxContextProvider <DevToolboxContextProvider
isDev={process.env.NODE_ENV !== "production"} isDev={process.env.NODE_ENV !== "production"}
> >
<main className="p-8 w-full overflow-visible">{children}</main> <main className="p-8 w-full overflow-visible">
<Toaster /> {children}
</main>
</DevToolboxContextProvider> </DevToolboxContextProvider>
</JotaiProvider>
</RecoilRootClient> </RecoilRootClient>
<div id="root-portal"></div> <div id="root-portal"></div>
</body> </body>

View File

@ -11,7 +11,8 @@ export default function Home() {
<h2 className="strapline">Tabletop Commander</h2> <h2 className="strapline">Tabletop Commander</h2>
<h1>How does it work?</h1> <h1>How does it work?</h1>
</section> </section>
{/* <section className="w-full my-6"> {
/* <section className="w-full my-6">
<div className="card"> <div className="card">
<p> <p>
Tabletop Commander (TC) is a rules-and-tools app for tabletop games Tabletop Commander (TC) is a rules-and-tools app for tabletop games
@ -130,7 +131,8 @@ export default function Home() {
will be done. If this makes it to production, tell Emma she forgot to will be done. If this makes it to production, tell Emma she forgot to
turn the home page into magic turn the home page into magic
</cite> </cite>
</section> */} </section> */
}
<Suspense fallback={<MDSkeletonLoader />}> <Suspense fallback={<MDSkeletonLoader />}>
<HomeClient body={body} /> <HomeClient body={body} />
</Suspense> </Suspense>

View File

@ -1,7 +0,0 @@
"use client";
import { Provider } from "jotai";
export function JotaiProvider(props: React.PropsWithChildren) {
return <Provider>{props.children}</Provider>;
}

View File

@ -12,7 +12,6 @@ import { TemplateEditor } from "./template-editor";
import { Icon } from "@/components/Icon"; import { Icon } from "@/components/Icon";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import { FieldTypes } from "./fieldtypes"; import { FieldTypes } from "./fieldtypes";
import { prisma } from "@/prisma/prismaClient";
export const SchemaBuilder: FC = () => { export const SchemaBuilder: FC = () => {
const [schema, setSchema] = useRecoilState(SchemaEditAtom); const [schema, setSchema] = useRecoilState(SchemaEditAtom);
@ -20,16 +19,10 @@ export const SchemaBuilder: FC = () => {
const { update: updateSchema, bindProperty: bindSchemaProperty } = const { update: updateSchema, bindProperty: bindSchemaProperty } =
useObjectStateWrapper<Schema>(schema, setSchema); useObjectStateWrapper<Schema>(schema, setSchema);
const { schemaId, gameSystemId } = useParams<{ const { schemaId } = useParams<{ schemaId: string }>();
schemaId: string;
gameSystemId?: string;
}>();
const { const { value: typeName, bind: bindTypeName, reset: resetTypeName } =
value: typeName, useInput("");
bind: bindTypeName,
reset: resetTypeName,
} = useInput("");
const [pageNumber, setPageNumber] = useState(0); const [pageNumber, setPageNumber] = useState(0);
@ -37,8 +30,7 @@ export const SchemaBuilder: FC = () => {
const [selectedType, setSelectedType] = useState(""); const [selectedType, setSelectedType] = useState("");
const saveType = useCallback( const saveType = useCallback((name: string, type: TypeType) => {
(name: string, type: TypeType) => {
updateSchema((e) => ({ updateSchema((e) => ({
types: { types: {
...e.types, ...e.types,
@ -48,25 +40,13 @@ export const SchemaBuilder: FC = () => {
resetTypeName(); resetTypeName();
setPageNumber(0); setPageNumber(0);
setSelectedType(""); setSelectedType("");
}, }, [resetTypeName, updateSchema]);
[resetTypeName, updateSchema]
);
const saveSchema = useCallback(async () => { const saveSchema = useCallback(async () => {
// "use server"; setLastSaved(schema);
// setLastSaved(schema); // const sid = await GameSystemsService.saveSchema(schema);
// await prisma.schema.upsert({ // if (schemaId === 'new') navigate('/schema/'+sid)
// where: { id: schema.id }, }, [schema]);
// update: { ...schema },
// create: {
// name: schema.name,
// schema: schema.schema,
// types: schema.types,
// version: 0,
// gameSystemId,
// },
// });
}, [schema, gameSystemId]);
const selectTypeForEdit = useCallback((typeKey: string) => { const selectTypeForEdit = useCallback((typeKey: string) => {
setSelectedType(typeKey); setSelectedType(typeKey);
@ -91,28 +71,22 @@ export const SchemaBuilder: FC = () => {
resetSchemaFieldName(); resetSchemaFieldName();
}, [resetSchemaFieldName, schemaFieldName, updateSchema]); }, [resetSchemaFieldName, schemaFieldName, updateSchema]);
const updateSchemaField = useCallback( const updateSchemaField = useCallback((key: string, template: Template) => {
(key: string, template: Template) => {
updateSchema((s) => ({ updateSchema((s) => ({
schema: { schema: {
...s.schema, ...s.schema,
[key]: template, [key]: template,
}, },
})); }));
}, }, [updateSchema]);
[updateSchema]
);
const deleteType = useCallback( const deleteType = useCallback((key: string) => {
(key: string) => {
updateSchema((s) => { updateSchema((s) => {
const types = { ...s.types }; const types = { ...s.types };
delete types[key]; delete types[key];
return { types }; return { types };
}); });
}, }, [updateSchema]);
[updateSchema]
);
return ( return (
<div className="flex gap-4 p-8"> <div className="flex gap-4 p-8">
@ -133,16 +107,16 @@ export const SchemaBuilder: FC = () => {
</button> </button>
</div> </div>
<ul className="rounded-lg overflow-hidden"> <ul className="rounded-lg overflow-hidden">
{Object.entries(schema.schema).map( {Object.entries(schema.schema).map((
([schemaFieldKey, schemaField]) => ( [schemaFieldKey, schemaField],
) => (
<TemplateEditor <TemplateEditor
key={schemaFieldKey} key={schemaFieldKey}
templateKey={schemaFieldKey} templateKey={schemaFieldKey}
template={schemaField} template={schemaField}
update={updateSchemaField} update={updateSchemaField}
/> />
) ))}
)}
</ul> </ul>
</div> </div>
<hr /> <hr />
@ -162,11 +136,9 @@ export const SchemaBuilder: FC = () => {
<TypeEditor <TypeEditor
name={selectedType || typeName} name={selectedType || typeName}
saveType={saveType} saveType={saveType}
type={ type={selectedType
selectedType
? schema.types[selectedType as keyof typeof schema.types] ? schema.types[selectedType as keyof typeof schema.types]
: undefined : undefined}
}
/> />
</AnimatedPageContainer> </AnimatedPageContainer>
<ul className="mt-3 w-96"> <ul className="mt-3 w-96">

View File

@ -1,111 +0,0 @@
"use client";
import { Portal } from "@/lib/portal/components";
import { atom, useAtom } from "jotai";
import React, { useCallback, useEffect, useState } from "react";
import { ReactNode } from "react";
type toastMessage = {
msg: ReactNode;
type?: "error" | "default";
fading: boolean;
duration?: number;
};
type IDToastMessage = toastMessage & {
id: string;
};
const toastAtom = atom<IDToastMessage[]>([]);
export function useToast() {
const [_, setToasts] = useAtom(toastAtom);
const createToast = useCallback(
(t: toastMessage) => {
const idd = { ...t, id: crypto.randomUUID() };
setToasts((toasts) => {
return [...toasts, idd];
});
return idd;
},
[setToasts]
);
const clearToast = useCallback(
(t: toastMessage) => setToasts((toasts) => toasts.filter((to) => to != t)),
[setToasts]
);
return {
createToast,
clearToast,
};
}
export function Toaster() {
const [toasts, setToasts] = useAtom(toastAtom);
const clearToast = useCallback(
(t: toastMessage) => {
setToasts((toasts) => {
return toasts.filter((to) => to !== t);
});
},
[setToasts]
);
if (!toasts.length) return <></>;
return (
<Portal>
<div className="fixed bottom-12 left-1/2 -translate-x-1/2 max-w-[95vw] flex flex-col gap-4">
{toasts.map((t) => (
<Toast key={"toast " + t.id} toast={t} clearToast={clearToast} />
))}
</div>
</Portal>
);
}
function Toast(props: {
toast: toastMessage;
clearToast: (t: toastMessage) => void;
}) {
const { toast, clearToast } = props;
const [fading, setFading] = useState(false);
const clear = useCallback(() => {
setFading(true);
setTimeout(() => {
clearToast(toast);
}, 300);
}, [clearToast, toast]);
const fadeOut = useCallback(() => {
setTimeout(clear, toast.duration ?? 3000);
}, [clear, toast]);
useEffect(() => {
if (!toast.fading) return;
fadeOut();
}, [fadeOut, toast]);
return (
<div
data-fading={fading}
data-type={toast.type}
className="relative p-6 px-16 toast data-[fading=true]:fade-toast rounded-md bg-mixed-300 data-[type=error]:bg-red-900 border-2 border-mixed-400 data-[type=error]:border-red-700"
>
{toast.msg}
{!toast.fading && (
<button
className="top-2 right-2 text-xs absolute"
onClick={() => clear()}
>
Dismiss
</button>
)}
</div>
);
}

View File

@ -30,6 +30,7 @@ export function OnDemandResolver({
const stackIdxs = Array.from(new Set(template.match(/\$\d/g))); const stackIdxs = Array.from(new Set(template.match(/\$\d/g)));
for (const idx of stackIdxs) { for (const idx of stackIdxs) {
let thing = res.current.getFromStack(idx); let thing = res.current.getFromStack(idx);
debugger;
if (Array.isArray(thing)) thing = thing.at(0); if (Array.isArray(thing)) thing = thing.at(0);
if (typeof thing === "function") thing = thing(); if (typeof thing === "function") thing = thing();
content = content.replaceAll(idx, thing as string); content = content.replaceAll(idx, thing as string);

View File

@ -239,6 +239,7 @@ export const buildOnlyDefaultElements = () => {
"ordered-list", "ordered-list",
/(?<=\n\n|^)\s*\d+\.\s([\s\S]*?)(?=\n\n|$)/g, /(?<=\n\n|^)\s*\d+\.\s([\s\S]*?)(?=\n\n|$)/g,
(s, rx) => { (s, rx) => {
// debugger;
return { return {
content: content:
s.match(new RegExp(rx, ""))?.at(0) || "Unable to parse ordered list", s.match(new RegExp(rx, ""))?.at(0) || "Unable to parse ordered list",
@ -253,6 +254,7 @@ export const buildOnlyDefaultElements = () => {
}, },
(token) => { (token) => {
const { children } = token; const { children } = token;
debugger;
return ( return (
<> <>
<ol <ol

View File

@ -27,6 +27,7 @@ export class TTCQueryResolver {
const last = this.stack.at(-1); const last = this.stack.at(-1);
if (typeof last === "function" && !onDemand) return last(); if (typeof last === "function" && !onDemand) return last();
if (onDemand) debugger;
return last; return last;
} }

244
package-lock.json generated
View File

@ -9,10 +9,10 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@heroicons/react": "^2.1.1", "@heroicons/react": "^2.1.1",
"@prisma/client": "^5.18.0", "@prisma/client": "^5.11.0",
"isomorphic-dompurify": "^2.4.0", "isomorphic-dompurify": "^2.4.0",
"jotai": "^2.9.3", "next": "14.1.0",
"next": "^14.2.5", "prisma": "^5.11.0",
"react": "^18", "react": "^18",
"react-dom": "^18", "react-dom": "^18",
"recoil": "^0.7.7" "recoil": "^0.7.7"
@ -26,7 +26,6 @@
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "14.1.0", "eslint-config-next": "14.1.0",
"postcss": "^8", "postcss": "^8",
"prisma": "^5.18.0",
"tailwindcss": "^3.3.0", "tailwindcss": "^3.3.0",
"typescript": "^5", "typescript": "^5",
"typescript-eslint": "^7.2.0" "typescript-eslint": "^7.2.0"
@ -2279,9 +2278,7 @@
} }
}, },
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz",
"integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@next/eslint-plugin-next": { "node_modules/@next/eslint-plugin-next": {
@ -2293,13 +2290,12 @@
} }
}, },
"node_modules/@next/swc-darwin-arm64": { "node_modules/@next/swc-darwin-arm64": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.0.tgz",
"integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", "integrity": "sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
@ -2309,13 +2305,12 @@
} }
}, },
"node_modules/@next/swc-darwin-x64": { "node_modules/@next/swc-darwin-x64": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.0.tgz",
"integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", "integrity": "sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
@ -2325,13 +2320,12 @@
} }
}, },
"node_modules/@next/swc-linux-arm64-gnu": { "node_modules/@next/swc-linux-arm64-gnu": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.0.tgz",
"integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", "integrity": "sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
@ -2341,13 +2335,12 @@
} }
}, },
"node_modules/@next/swc-linux-arm64-musl": { "node_modules/@next/swc-linux-arm64-musl": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.0.tgz",
"integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", "integrity": "sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
@ -2357,9 +2350,7 @@
} }
}, },
"node_modules/@next/swc-linux-x64-gnu": { "node_modules/@next/swc-linux-x64-gnu": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz",
"integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2373,9 +2364,7 @@
} }
}, },
"node_modules/@next/swc-linux-x64-musl": { "node_modules/@next/swc-linux-x64-musl": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz",
"integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2389,13 +2378,12 @@
} }
}, },
"node_modules/@next/swc-win32-arm64-msvc": { "node_modules/@next/swc-win32-arm64-msvc": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.0.tgz",
"integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", "integrity": "sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
@ -2405,13 +2393,12 @@
} }
}, },
"node_modules/@next/swc-win32-ia32-msvc": { "node_modules/@next/swc-win32-ia32-msvc": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.0.tgz",
"integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", "integrity": "sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
@ -2421,13 +2408,12 @@
} }
}, },
"node_modules/@next/swc-win32-x64-msvc": { "node_modules/@next/swc-win32-x64-msvc": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.0.tgz",
"integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", "integrity": "sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
@ -2478,11 +2464,10 @@
} }
}, },
"node_modules/@prisma/client": { "node_modules/@prisma/client": {
"version": "5.18.0", "version": "5.11.0",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.18.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.11.0.tgz",
"integrity": "sha512-BWivkLh+af1kqC89zCJYkHsRcyWsM8/JHpsDMM76DjP3ZdEquJhXa4IeX+HkWPnwJ5FanxEJFZZDTWiDs/Kvyw==", "integrity": "sha512-SWshvS5FDXvgJKM/a0y9nDC1rqd7KG0Q6ZVzd+U7ZXK5soe73DJxJJgbNBt2GNXOa+ysWB4suTpdK5zfFPhwiw==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0",
"engines": { "engines": {
"node": ">=16.13" "node": ">=16.13"
}, },
@ -2496,53 +2481,43 @@
} }
}, },
"node_modules/@prisma/debug": { "node_modules/@prisma/debug": {
"version": "5.18.0", "version": "5.11.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.18.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.11.0.tgz",
"integrity": "sha512-f+ZvpTLidSo3LMJxQPVgAxdAjzv5OpzAo/eF8qZqbwvgi2F5cTOI9XCpdRzJYA0iGfajjwjOKKrVq64vkxEfUw==", "integrity": "sha512-N6yYr3AbQqaiUg+OgjkdPp3KPW1vMTAgtKX6+BiB/qB2i1TjLYCrweKcUjzOoRM5BriA4idrkTej9A9QqTfl3A=="
"devOptional": true,
"license": "Apache-2.0"
}, },
"node_modules/@prisma/engines": { "node_modules/@prisma/engines": {
"version": "5.18.0", "version": "5.11.0",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.18.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.11.0.tgz",
"integrity": "sha512-ofmpGLeJ2q2P0wa/XaEgTnX/IsLnvSp/gZts0zjgLNdBhfuj2lowOOPmDcfKljLQUXMvAek3lw5T01kHmCG8rg==", "integrity": "sha512-gbrpQoBTYWXDRqD+iTYMirDlF9MMlQdxskQXbhARhG6A/uFQjB7DZMYocMQLoiZXO/IskfDOZpPoZE8TBQKtEw==",
"devOptional": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@prisma/debug": "5.18.0", "@prisma/debug": "5.11.0",
"@prisma/engines-version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", "@prisma/engines-version": "5.11.0-15.efd2449663b3d73d637ea1fd226bafbcf45b3102",
"@prisma/fetch-engine": "5.18.0", "@prisma/fetch-engine": "5.11.0",
"@prisma/get-platform": "5.18.0" "@prisma/get-platform": "5.11.0"
} }
}, },
"node_modules/@prisma/engines-version": { "node_modules/@prisma/engines-version": {
"version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", "version": "5.11.0-15.efd2449663b3d73d637ea1fd226bafbcf45b3102",
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169.tgz", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.11.0-15.efd2449663b3d73d637ea1fd226bafbcf45b3102.tgz",
"integrity": "sha512-a/+LpJj8vYU3nmtkg+N3X51ddbt35yYrRe8wqHTJtYQt7l1f8kjIBcCs6sHJvodW/EK5XGvboOiwm47fmNrbgg==", "integrity": "sha512-WXCuyoymvrS4zLz4wQagSsc3/nE6CHy8znyiMv8RKazKymOMd5o9FP5RGwGHAtgoxd+aB/BWqxuP/Ckfu7/3MA=="
"devOptional": true,
"license": "Apache-2.0"
}, },
"node_modules/@prisma/fetch-engine": { "node_modules/@prisma/fetch-engine": {
"version": "5.18.0", "version": "5.11.0",
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.18.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.11.0.tgz",
"integrity": "sha512-I/3u0x2n31rGaAuBRx2YK4eB7R/1zCuayo2DGwSpGyrJWsZesrV7QVw7ND0/Suxeo/vLkJ5OwuBqHoCxvTHpOg==", "integrity": "sha512-994viazmHTJ1ymzvWugXod7dZ42T2ROeFuH6zHPcUfp/69+6cl5r9u3NFb6bW8lLdNjwLYEVPeu3hWzxpZeC0w==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@prisma/debug": "5.18.0", "@prisma/debug": "5.11.0",
"@prisma/engines-version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", "@prisma/engines-version": "5.11.0-15.efd2449663b3d73d637ea1fd226bafbcf45b3102",
"@prisma/get-platform": "5.18.0" "@prisma/get-platform": "5.11.0"
} }
}, },
"node_modules/@prisma/get-platform": { "node_modules/@prisma/get-platform": {
"version": "5.18.0", "version": "5.11.0",
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.18.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.11.0.tgz",
"integrity": "sha512-Tk+m7+uhqcKDgnMnFN0lRiH7Ewea0OEsZZs9pqXa7i3+7svS3FSCqDBCaM9x5fmhhkufiG0BtunJVDka+46DlA==", "integrity": "sha512-rxtHpMLxNTHxqWuGOLzR2QOyQi79rK1u1XYAVLZxDGTLz/A+uoDnjz9veBFlicrpWjwuieM4N6jcnjj/DDoidw==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@prisma/debug": "5.18.0" "@prisma/debug": "5.11.0"
} }
}, },
"node_modules/@rushstack/eslint-patch": { "node_modules/@rushstack/eslint-patch": {
@ -2807,19 +2782,10 @@
"url": "https://github.com/sponsors/gregberge" "url": "https://github.com/sponsors/gregberge"
} }
}, },
"node_modules/@swc/counter": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
"license": "Apache-2.0"
},
"node_modules/@swc/helpers": { "node_modules/@swc/helpers": {
"version": "0.5.5", "version": "0.5.2",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz",
"integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@swc/counter": "^0.1.3",
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
@ -2859,12 +2825,12 @@
}, },
"node_modules/@types/prop-types": { "node_modules/@types/prop-types": {
"version": "15.7.11", "version": "15.7.11",
"devOptional": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "18.2.58", "version": "18.2.58",
"devOptional": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
@ -2882,7 +2848,7 @@
}, },
"node_modules/@types/scheduler": { "node_modules/@types/scheduler": {
"version": "0.16.8", "version": "0.16.8",
"devOptional": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/semver": { "node_modules/@types/semver": {
@ -3912,13 +3878,11 @@
} }
}, },
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.3", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fill-range": "^7.1.1" "fill-range": "^7.0.1"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@ -4275,7 +4239,7 @@
}, },
"node_modules/csstype": { "node_modules/csstype": {
"version": "3.1.3", "version": "3.1.3",
"devOptional": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/damerau-levenshtein": { "node_modules/damerau-levenshtein": {
@ -5127,9 +5091,7 @@
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.1.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -5224,21 +5186,6 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "version": "1.1.2",
"dev": true, "dev": true,
@ -5807,8 +5754,6 @@
}, },
"node_modules/is-number": { "node_modules/is-number": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -6010,27 +5955,6 @@
"jiti": "bin/jiti.js" "jiti": "bin/jiti.js"
} }
}, },
"node_modules/jotai": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/jotai/-/jotai-2.9.3.tgz",
"integrity": "sha512-IqMWKoXuEzWSShjd9UhalNsRGbdju5G2FrqNLQJT+Ih6p41VNYe2sav5hnwQx4HJr25jq9wRqvGSWGviGG6Gjw==",
"license": "MIT",
"engines": {
"node": ">=12.20.0"
},
"peerDependencies": {
"@types/react": ">=17.0.0",
"react": ">=17.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"react": {
"optional": true
}
}
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"license": "MIT" "license": "MIT"
@ -6352,13 +6276,11 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/next": { "node_modules/next": {
"version": "14.2.5", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz",
"integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@next/env": "14.2.5", "@next/env": "14.1.0",
"@swc/helpers": "0.5.5", "@swc/helpers": "0.5.2",
"busboy": "1.6.0", "busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579", "caniuse-lite": "^1.0.30001579",
"graceful-fs": "^4.2.11", "graceful-fs": "^4.2.11",
@ -6372,19 +6294,18 @@
"node": ">=18.17.0" "node": ">=18.17.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@next/swc-darwin-arm64": "14.2.5", "@next/swc-darwin-arm64": "14.1.0",
"@next/swc-darwin-x64": "14.2.5", "@next/swc-darwin-x64": "14.1.0",
"@next/swc-linux-arm64-gnu": "14.2.5", "@next/swc-linux-arm64-gnu": "14.1.0",
"@next/swc-linux-arm64-musl": "14.2.5", "@next/swc-linux-arm64-musl": "14.1.0",
"@next/swc-linux-x64-gnu": "14.2.5", "@next/swc-linux-x64-gnu": "14.1.0",
"@next/swc-linux-x64-musl": "14.2.5", "@next/swc-linux-x64-musl": "14.1.0",
"@next/swc-win32-arm64-msvc": "14.2.5", "@next/swc-win32-arm64-msvc": "14.1.0",
"@next/swc-win32-ia32-msvc": "14.2.5", "@next/swc-win32-ia32-msvc": "14.1.0",
"@next/swc-win32-x64-msvc": "14.2.5" "@next/swc-win32-x64-msvc": "14.1.0"
}, },
"peerDependencies": { "peerDependencies": {
"@opentelemetry/api": "^1.1.0", "@opentelemetry/api": "^1.1.0",
"@playwright/test": "^1.41.2",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"sass": "^1.3.0" "sass": "^1.3.0"
@ -6393,9 +6314,6 @@
"@opentelemetry/api": { "@opentelemetry/api": {
"optional": true "optional": true
}, },
"@playwright/test": {
"optional": true
},
"sass": { "sass": {
"optional": true "optional": true
} }
@ -6932,14 +6850,12 @@
} }
}, },
"node_modules/prisma": { "node_modules/prisma": {
"version": "5.18.0", "version": "5.11.0",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.18.0.tgz", "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.11.0.tgz",
"integrity": "sha512-+TrSIxZsh64OPOmaSgVPH7ALL9dfU0jceYaMJXsNrTkFHO7/3RANi5K2ZiPB1De9+KDxCWn7jvRq8y8pvk+o9g==", "integrity": "sha512-KCLiug2cs0Je7kGkQBN9jDWoZ90ogE/kvZTUTgz2h94FEo8pczCkPH7fPNXkD1sGU7Yh65risGGD1HQ5DF3r3g==",
"devOptional": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@prisma/engines": "5.18.0" "@prisma/engines": "5.11.0"
}, },
"bin": { "bin": {
"prisma": "build/index.js" "prisma": "build/index.js"
@ -7756,8 +7672,6 @@
}, },
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -8387,9 +8301,7 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.18.0", "version": "8.16.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"

View File

@ -10,10 +10,10 @@
}, },
"dependencies": { "dependencies": {
"@heroicons/react": "^2.1.1", "@heroicons/react": "^2.1.1",
"@prisma/client": "^5.18.0", "@prisma/client": "^5.11.0",
"isomorphic-dompurify": "^2.4.0", "isomorphic-dompurify": "^2.4.0",
"jotai": "^2.9.3", "next": "14.1.0",
"next": "^14.2.5", "prisma": "^5.11.0",
"react": "^18", "react": "^18",
"react-dom": "^18", "react-dom": "^18",
"recoil": "^0.7.7" "recoil": "^0.7.7"
@ -27,7 +27,6 @@
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "14.1.0", "eslint-config-next": "14.1.0",
"postcss": "^8", "postcss": "^8",
"prisma": "^5.18.0",
"tailwindcss": "^3.3.0", "tailwindcss": "^3.3.0",
"typescript": "^5", "typescript": "^5",
"typescript-eslint": "^7.2.0" "typescript-eslint": "^7.2.0"

View File

@ -1,83 +0,0 @@
/*
Warnings:
- Added the required column `authorId` to the `GameSystem` table without a default value. This is not possible if the table is not empty.
- Added the required column `authorId` to the `Publication` table without a default value. This is not possible if the table is not empty.
- Added the required column `authorId` to the `Schema` table without a default value. This is not possible if the table is not empty.
- Added the required column `originalId` to the `Schema` table without a default value. This is not possible if the table is not empty.
- Added the required column `name` to the `Tag` table without a default value. This is not possible if the table is not empty.
*/
-- DropForeignKey
ALTER TABLE `Schema` DROP FOREIGN KEY `Schema_gameSystemId_fkey`;
-- DropForeignKey
ALTER TABLE `Tag` DROP FOREIGN KEY `Tag_publicationId_fkey`;
-- AlterTable
ALTER TABLE `GameSystem` ADD COLUMN `authorId` VARCHAR(191) NOT NULL;
-- AlterTable
ALTER TABLE `Publication` ADD COLUMN `authorId` VARCHAR(191) NOT NULL;
-- AlterTable
ALTER TABLE `Schema` ADD COLUMN `authorId` VARCHAR(191) NOT NULL,
ADD COLUMN `originalId` VARCHAR(191) NOT NULL,
MODIFY `gameSystemId` VARCHAR(191) NULL;
-- AlterTable
ALTER TABLE `Tag` ADD COLUMN `name` VARCHAR(191) NOT NULL,
MODIFY `publicationId` VARCHAR(191) NULL;
-- CreateTable
CREATE TABLE `TagsOnPublications` (
`publicationId` VARCHAR(191) NOT NULL,
`tagId` VARCHAR(191) NOT NULL,
PRIMARY KEY (`publicationId`, `tagId`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `TagsOnTags` (
`parentTagId` VARCHAR(191) NOT NULL,
`childTagId` VARCHAR(191) NOT NULL,
PRIMARY KEY (`parentTagId`, `childTagId`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `User` (
`id` VARCHAR(191) NOT NULL,
`username` VARCHAR(191) NOT NULL,
`email` VARCHAR(191) NOT NULL,
UNIQUE INDEX `User_email_key`(`email`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `GameSystem` ADD CONSTRAINT `GameSystem_authorId_fkey` FOREIGN KEY (`authorId`) REFERENCES `User`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Schema` ADD CONSTRAINT `Schema_gameSystemId_fkey` FOREIGN KEY (`gameSystemId`) REFERENCES `GameSystem`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Schema` ADD CONSTRAINT `Schema_authorId_fkey` FOREIGN KEY (`authorId`) REFERENCES `User`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Publication` ADD CONSTRAINT `Publication_authorId_fkey` FOREIGN KEY (`authorId`) REFERENCES `User`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `TagsOnPublications` ADD CONSTRAINT `TagsOnPublications_publicationId_fkey` FOREIGN KEY (`publicationId`) REFERENCES `Publication`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `TagsOnPublications` ADD CONSTRAINT `TagsOnPublications_tagId_fkey` FOREIGN KEY (`tagId`) REFERENCES `Tag`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Tag` ADD CONSTRAINT `Tag_publicationId_fkey` FOREIGN KEY (`publicationId`) REFERENCES `Publication`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `TagsOnTags` ADD CONSTRAINT `TagsOnTags_parentTagId_fkey` FOREIGN KEY (`parentTagId`) REFERENCES `Tag`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `TagsOnTags` ADD CONSTRAINT `TagsOnTags_childTagId_fkey` FOREIGN KEY (`childTagId`) REFERENCES `Tag`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -25,8 +25,8 @@ model GameSystem {
model Schema { model Schema {
id String @id @default(cuid()) id String @id @default(cuid())
gameSystem GameSystem? @relation(fields: [gameSystemId], references: [id]) gameSystem GameSystem @relation(fields: [gameSystemId], references: [id])
gameSystemId String? gameSystemId String
publications Publication[] publications Publication[]
author User @relation(fields: [authorId], references: [id]) author User @relation(fields: [authorId], references: [id])
authorId String authorId String
@ -48,35 +48,12 @@ model Publication {
name String name String
data Json data Json
TagsOnPublications TagsOnPublications[]
}
model TagsOnPublications {
publication Publication @relation(fields: [publicationId], references: [id])
publicationId String
tagId String
tag Tag @relation(fields: [tagId], references: [id])
@@id([publicationId, tagId])
} }
model Tag { model Tag {
id String @id @default(cuid()) id String @id @default(cuid())
name String publication Publication @relation(fields: [publicationId], references: [id])
Publication Publication? @relation(fields: [publicationId], references: [id]) publicationId String
publicationId String?
TagsOnPublications TagsOnPublications[]
childTagsOnTags TagsOnTags[] @relation("childTag")
parentTagsOnTags TagsOnTags[] @relation("parentTag")
}
model TagsOnTags {
parentTagId String
parentTag Tag @relation(fields: [parentTagId], references: [id], "parentTag")
childTagId String
childTag Tag @relation(fields: [childTagId], references: [id], "childTag")
@@id([parentTagId, childTagId])
} }
model User { model User {