mirror of
https://github.com/jordienr/zenblog.git
synced 2026-09-28 01:56:07 -04:00
wip
This commit is contained in:
@@ -359,19 +359,21 @@ export const ZendoEditor = (props: Props) => {
|
||||
align="start"
|
||||
className="-mt-1 max-w-[240px]"
|
||||
>
|
||||
{postsQuery.data?.map((post) => (
|
||||
<DropdownMenuItem key={post.post_id} asChild>
|
||||
<Link
|
||||
href={`/blogs/${blogId}/post/${post.slug}`}
|
||||
className="flex gap-2 px-2 py-1 hover:bg-zinc-100"
|
||||
>
|
||||
<span className="text-xs">
|
||||
{post.published ? "🟢" : "🟠"}
|
||||
</span>
|
||||
<span>{post.title}</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
{postsQuery.data?.pages
|
||||
.flatMap((page) => page.data)
|
||||
.map((post) => (
|
||||
<DropdownMenuItem key={post.post_id} asChild>
|
||||
<Link
|
||||
href={`/blogs/${blogId}/post/${post.slug}`}
|
||||
className="flex gap-2 px-2 py-1 hover:bg-zinc-100"
|
||||
>
|
||||
<span className="text-xs">
|
||||
{post.published ? "🟢" : "🟠"}
|
||||
</span>
|
||||
<span>{post.title}</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
|
||||
@@ -22,7 +22,7 @@ const UserButton = (props: Props) => {
|
||||
<DropdownMenuTrigger className="flex items-center gap-2 rounded-full">
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-7 w-7 items-center justify-center rounded-full bg-zinc-800 font-bold text-white"
|
||||
"flex h-7 w-7 items-center justify-center rounded-full bg-gradient-to-b from-slate-700 to-slate-900 font-bold text-white transition-all hover:brightness-125"
|
||||
)}
|
||||
>
|
||||
{user?.email?.slice(0, 1).toUpperCase()}
|
||||
|
||||
@@ -77,16 +77,21 @@ export default function AppLayout({
|
||||
<div className={`flex min-h-screen flex-col border-b bg-zinc-50 font-sans`}>
|
||||
<TooltipProvider>
|
||||
<AppChecks>
|
||||
<nav className="mx-auto w-full bg-white">
|
||||
<nav
|
||||
className={cn("mx-auto w-full bg-white", {
|
||||
"border-b shadow-sm": !selectedBlog,
|
||||
})}
|
||||
>
|
||||
<div className="mx-auto flex h-full max-w-5xl items-center justify-between px-2">
|
||||
<div className="flex h-full items-center py-3">
|
||||
{!selectedBlog && (
|
||||
<Link
|
||||
tabIndex={-1}
|
||||
href="/blogs"
|
||||
className="flex items-center justify-center rounded-xl py-4 text-lg font-medium"
|
||||
className="flex items-center justify-center rounded-xl px-1 py-4 text-lg font-medium"
|
||||
>
|
||||
<ZendoLogo hideText />
|
||||
<span className="ml-2">zenblog</span>
|
||||
</Link>
|
||||
)}
|
||||
{selectedBlog && (
|
||||
@@ -155,7 +160,7 @@ export default function AppLayout({
|
||||
Skip to content
|
||||
</a>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center gap-1 pr-2">
|
||||
<Feedback />
|
||||
{/* <Link
|
||||
className="rounded-full px-3 py-4 text-sm font-medium text-slate-600 hover:text-orange-600"
|
||||
@@ -170,27 +175,27 @@ export default function AppLayout({
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{selectedBlog && (
|
||||
<div className="border-b bg-white shadow-sm">
|
||||
<div className="mx-auto flex max-w-5xl items-center px-2">
|
||||
{BlogNavItems.map((item) => (
|
||||
<NavItem
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
selected={item.href === router.asPath}
|
||||
>
|
||||
{item.label}
|
||||
</NavItem>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{loading ? (
|
||||
<div className="flex h-[600px] items-center justify-center">
|
||||
<Loader className="animate-spin text-orange-500" size={32} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="">
|
||||
{selectedBlog && (
|
||||
<div className="border-b bg-white">
|
||||
<div className="mx-auto flex max-w-5xl items-center px-2">
|
||||
{BlogNavItems.map((item) => (
|
||||
<NavItem
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
selected={item.href === router.asPath}
|
||||
>
|
||||
{item.label}
|
||||
</NavItem>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="mx-auto flex max-w-5xl items-center justify-between px-4 py-4">
|
||||
<SectionTitle>{title}</SectionTitle>
|
||||
<SectionActions>{actions}</SectionActions>
|
||||
@@ -227,7 +232,7 @@ function NavItem({
|
||||
<Link
|
||||
href={href}
|
||||
className={cn(
|
||||
`relative flex items-center gap-1 px-2 py-2 text-sm font-medium text-zinc-600 md:px-2 md:py-1`,
|
||||
`relative flex items-center gap-1 rounded-md px-2 py-2 text-sm font-medium text-zinc-600 hover:bg-zinc-50 md:px-2 md:py-1`,
|
||||
{
|
||||
"text-zinc-950": selected,
|
||||
"after:absolute after:inset-x-0 after:bottom-[-1px] after:z-10 after:h-[2px] after:w-full after:bg-orange-500 after:content-['']":
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ConfirmDialog } from "@/components/confirm-dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -6,6 +7,12 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
@@ -18,8 +25,14 @@ import {
|
||||
} from "@/components/ui/table";
|
||||
import { useBlogId } from "@/hooks/use-blog-id";
|
||||
import AppLayout, { Section } from "@/layouts/AppLayout";
|
||||
import { useCategories, useCreateCategory } from "@/queries/categories";
|
||||
import { Plus } from "lucide-react";
|
||||
import {
|
||||
useCategories,
|
||||
useCategoriesWithPostCount,
|
||||
useCreateCategory,
|
||||
useDeleteCategoryMutation,
|
||||
useUpdateCategoryMutation,
|
||||
} from "@/queries/categories";
|
||||
import { MoreHorizontal, Plus } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
@@ -42,19 +55,24 @@ export function CreateCategoryDialog() {
|
||||
</DialogHeader>
|
||||
<form
|
||||
className="[&_input]:mb-3 [&_input]:mt-1"
|
||||
onSubmit={(e) => {
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const formData = new FormData(e.target as HTMLFormElement);
|
||||
const name = formData.get("name");
|
||||
const slug = formData.get("slug");
|
||||
createCategory.mutate({
|
||||
name: name as string,
|
||||
slug: slug as string,
|
||||
blog_id: blogId,
|
||||
});
|
||||
toast.success("Category created");
|
||||
setOpen(false);
|
||||
|
||||
try {
|
||||
await createCategory.mutateAsync({
|
||||
name: name as string,
|
||||
slug: slug as string,
|
||||
blog_id: blogId,
|
||||
});
|
||||
toast.success("Category created");
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
toast.error("Failed to create category. Slugs must be unique.");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Label htmlFor="name">Name</Label>
|
||||
@@ -71,12 +89,25 @@ export function CreateCategoryDialog() {
|
||||
}
|
||||
|
||||
export default function CategoriesPage() {
|
||||
const categories = useCategories();
|
||||
const blogId = useBlogId();
|
||||
|
||||
const { data: categories, isLoading } = useCategoriesWithPostCount();
|
||||
const [selectedCategory, setSelectedCategory] = useState<{
|
||||
category_id: number | null;
|
||||
category_name: string | null;
|
||||
category_slug: string | null;
|
||||
} | null>(null);
|
||||
|
||||
const [updateCategoryOpen, setUpdateCategoryOpen] = useState(false);
|
||||
const updateCategory = useUpdateCategoryMutation();
|
||||
|
||||
const [deleteCategoryOpen, setDeleteCategoryOpen] = useState(false);
|
||||
const deleteCategory = useDeleteCategoryMutation(blogId);
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
title="Categories"
|
||||
loading={categories.isLoading}
|
||||
loading={isLoading}
|
||||
actions={<CreateCategoryDialog />}
|
||||
>
|
||||
<Section>
|
||||
@@ -85,21 +116,109 @@ export default function CategoriesPage() {
|
||||
<TableRow>
|
||||
<TableHead>Category</TableHead>
|
||||
<TableHead>Slug</TableHead>
|
||||
{/* <TableHead>Posts</TableHead> */}
|
||||
<TableHead></TableHead>
|
||||
<TableHead className="text-right">Posts with category</TableHead>
|
||||
<TableHead className="text-right">
|
||||
<div className="sr-only">Action</div>
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{categories.data?.map((category) => (
|
||||
<TableRow key={category.id}>
|
||||
<TableCell>{category.name}</TableCell>
|
||||
<TableCell>{category.slug}</TableCell>
|
||||
{/* <TableCell>{category.post_count}</TableCell> */}
|
||||
<TableCell></TableCell>
|
||||
{categories?.data?.map((category) => (
|
||||
<TableRow key={category.category_id}>
|
||||
<TableCell>{category.category_name}</TableCell>
|
||||
<TableCell>{category.category_slug}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{category.post_count}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon">
|
||||
<MoreHorizontal size={16} />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setSelectedCategory(category);
|
||||
setUpdateCategoryOpen(true);
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setSelectedCategory(category);
|
||||
setDeleteCategoryOpen(true);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Dialog open={updateCategoryOpen} onOpenChange={setUpdateCategoryOpen}>
|
||||
<DialogContent className="!max-w-sm">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit category</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const formData = new FormData(e.target as HTMLFormElement);
|
||||
const name = formData.get("name");
|
||||
const slug = formData.get("slug");
|
||||
if (!selectedCategory?.category_id) return;
|
||||
|
||||
await updateCategory.mutateAsync({
|
||||
id: selectedCategory.category_id,
|
||||
name: name as string,
|
||||
slug: slug as string,
|
||||
});
|
||||
|
||||
toast.success("Category updated");
|
||||
setUpdateCategoryOpen(false);
|
||||
}}
|
||||
>
|
||||
<Label htmlFor="name">Name</Label>
|
||||
<Input
|
||||
defaultValue={selectedCategory?.category_name ?? ""}
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder="Technology"
|
||||
/>
|
||||
<Label className="mt-4" htmlFor="slug">
|
||||
Slug
|
||||
</Label>
|
||||
<Input
|
||||
defaultValue={selectedCategory?.category_slug ?? ""}
|
||||
id="slug"
|
||||
name="slug"
|
||||
placeholder="technology"
|
||||
/>
|
||||
<div className="mt-4 flex justify-end">
|
||||
<Button type="submit">Update</Button>
|
||||
</div>
|
||||
</form>
|
||||
</DialogContent>
|
||||
|
||||
<ConfirmDialog
|
||||
open={deleteCategoryOpen}
|
||||
onOpenChange={setDeleteCategoryOpen}
|
||||
onConfirm={() => {
|
||||
if (!selectedCategory?.category_id) return;
|
||||
deleteCategory.mutate(selectedCategory.category_id.toString());
|
||||
toast.success("Category deleted");
|
||||
setDeleteCategoryOpen(false);
|
||||
}}
|
||||
/>
|
||||
</Dialog>
|
||||
</Section>
|
||||
</AppLayout>
|
||||
);
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function MediaPage() {
|
||||
{selectedImages.length > 0 && (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
setConfirmDeleteDialogOpen(true);
|
||||
}}
|
||||
@@ -73,9 +73,9 @@ export default function MediaPage() {
|
||||
)}
|
||||
<Dialog open={showUploadDialog} onOpenChange={setShowUploadDialog}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost">
|
||||
<Button variant="outline">
|
||||
<Upload size="16" />
|
||||
Upload
|
||||
Upload media
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="md:max-w-sm">
|
||||
|
||||
@@ -124,136 +124,6 @@ export default function BlogPosts() {
|
||||
</>
|
||||
}
|
||||
>
|
||||
{/* <Tabs
|
||||
value={tabValue || "posts"}
|
||||
onValueChange={(tabVal) => {
|
||||
onTabChange(tabVal);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<TabsList className="w-full items-center">
|
||||
<TabsTrigger value="posts">Posts</TabsTrigger>
|
||||
<TabsTrigger onClick={() => {}} value="media">
|
||||
Media
|
||||
</TabsTrigger>
|
||||
<TabsTrigger onClick={() => {}} value="categories">
|
||||
Categories
|
||||
</TabsTrigger>
|
||||
<TabsTrigger onClick={() => {}} value="tags">
|
||||
Tags
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
onClick={() => {
|
||||
router.push(`/blogs/${blogId}/settings`);
|
||||
}}
|
||||
value="settings"
|
||||
>
|
||||
Settings
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
|
||||
<TabsContent value="tags">
|
||||
<TabSection
|
||||
title={tags.data?.length ? `${tags.data?.length} tags` : "Tags"}
|
||||
actions={<></>}
|
||||
>
|
||||
<>
|
||||
{tags.isLoading && (
|
||||
<div className="p-12">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
{tags.data?.length === 0 && (
|
||||
<div className="p-12 py-32 text-center">
|
||||
<div className="text-2xl">🏷️</div>
|
||||
<div className="text-lg text-zinc-500">
|
||||
Nothing here yet
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid divide-y">
|
||||
{tags.data?.length ? (
|
||||
<div className="grid grid-cols-4 items-center p-2 text-sm font-medium text-zinc-600">
|
||||
<div>Tag</div>
|
||||
<div>Slug</div>
|
||||
<div className="text-right">Posts with tag</div>
|
||||
<div></div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{tags.data?.map((tag) => {
|
||||
return (
|
||||
<div
|
||||
key={tag.tag_id}
|
||||
className="grid grid-cols-4 items-center px-2 py-1.5 hover:bg-zinc-50"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<PiTag className="text-orange-500" size="16" />
|
||||
<span className="font-medium">{tag.tag_name}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<p className="font-mono text-sm text-zinc-500">
|
||||
{tag.slug}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="text-right font-mono">
|
||||
{tag.post_count}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end">
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size="icon" variant={"ghost"}>
|
||||
<MoreVertical size="16" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
if (!tag) {
|
||||
return;
|
||||
}
|
||||
setSelectedTag(tag);
|
||||
setUpdateTagDialogOpen(true);
|
||||
}}
|
||||
>
|
||||
<Pen size="16" className="mr-2" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
if (!tag) {
|
||||
return;
|
||||
}
|
||||
setSelectedTag(tag);
|
||||
setDeleteTagDialogOpen(true);
|
||||
}}
|
||||
>
|
||||
<Trash size="16" className="mr-2" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
</TabSection>
|
||||
</TabsContent>
|
||||
<TabsContent asChild value="categories">
|
||||
<TabSection title="Categories" actions={<></>}>
|
||||
<CategoriesPage />
|
||||
</TabSection>
|
||||
</TabsContent>
|
||||
</Tabs> */}
|
||||
|
||||
<Section>
|
||||
{posts.pages.length === 0 && (
|
||||
<div className="p-12 py-32 text-center">
|
||||
|
||||
@@ -20,20 +20,20 @@ export default function Dashboard() {
|
||||
const [hovering, setHovering] = useState("");
|
||||
|
||||
return (
|
||||
<AppLayout loading={isLoading}>
|
||||
<div className="mt-8 min-h-screen">
|
||||
<AppLayout
|
||||
loading={isLoading}
|
||||
title="My blogs"
|
||||
actions={
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/blogs/create">
|
||||
<Plus />
|
||||
Create blog
|
||||
</Link>
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<div className="min-h-screen">
|
||||
<div className="mx-auto max-w-5xl">
|
||||
<div className="flex items-center justify-between p-3">
|
||||
<h1 className="text-lg font-medium">My blogs</h1>
|
||||
<div>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/blogs/create">
|
||||
<Plus />
|
||||
Create blog
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{data?.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<div className="rounded-xl border bg-white p-2 shadow-sm">
|
||||
@@ -48,7 +48,7 @@ export default function Dashboard() {
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<ul className="mx-2 grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<ul className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
{data?.map((blog) => {
|
||||
return (
|
||||
<li
|
||||
|
||||
@@ -11,13 +11,26 @@ type Category = {
|
||||
blog_id: string;
|
||||
};
|
||||
|
||||
export function useCategoriesWithPostCount() {
|
||||
return useQuery({
|
||||
queryKey: ["categories-with-post-count"],
|
||||
queryFn: async () =>
|
||||
await sb
|
||||
.from("category_post_count")
|
||||
.select(
|
||||
"category_id, category_name, category_slug, post_count, created_at"
|
||||
)
|
||||
.throwOnError(),
|
||||
});
|
||||
}
|
||||
|
||||
export function useCategories() {
|
||||
return useQuery({
|
||||
queryKey: ["categories"],
|
||||
queryFn: async () => {
|
||||
const { data, error } = await sb
|
||||
.from("categories")
|
||||
.select("*")
|
||||
.select("id, slug, name, created_at")
|
||||
.throwOnError();
|
||||
if (error) {
|
||||
throw error;
|
||||
@@ -37,3 +50,58 @@ export function useCreateCategory() {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteCategoryMutation(blogId: string) {
|
||||
const queryClient = useQueryClient();
|
||||
const supa = createSupabaseBrowserClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (categoryId: string) => {
|
||||
const res = await supa
|
||||
.from("categories")
|
||||
.delete()
|
||||
.eq("id", categoryId)
|
||||
.eq("blog_id", blogId);
|
||||
|
||||
if (res.error) {
|
||||
throw new Error(res.error.message);
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["categories-with-post-count"],
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateCategoryMutation() {
|
||||
const queryClient = useQueryClient();
|
||||
const supa = createSupabaseBrowserClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (category: {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
}) => {
|
||||
const res = await supa
|
||||
.from("categories")
|
||||
.update(category)
|
||||
.eq("id", category.id);
|
||||
|
||||
if (res.error) {
|
||||
throw new Error(res.error.message);
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["categories-with-post-count"],
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
+29
-330
@@ -96,15 +96,7 @@ export type Database = {
|
||||
user_id?: string
|
||||
website?: string
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "blogs_user_id_fkey"
|
||||
columns: ["user_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "users"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
Relationships: []
|
||||
}
|
||||
categories: {
|
||||
Row: {
|
||||
@@ -237,13 +229,6 @@ export type Database = {
|
||||
referencedRelation: "posts_v5"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_blog_and_subscription_status"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
@@ -251,41 +236,6 @@ export type Database = {
|
||||
referencedRelation: "posts_with_blog_and_subscription_status_v2"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_tags"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_tags_v2"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_tags_v3"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "public_posts_v2"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "public_posts_v3"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_tag_id_fkey"
|
||||
columns: ["tag_id"]
|
||||
@@ -373,11 +323,11 @@ export type Database = {
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "public_posts_user_id_fkey"
|
||||
columns: ["user_id"]
|
||||
foreignKeyName: "posts_category_id_fkey"
|
||||
columns: ["category_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "users"
|
||||
referencedColumns: ["id"]
|
||||
referencedRelation: "category_post_count"
|
||||
referencedColumns: ["category_id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -445,15 +395,7 @@ export type Database = {
|
||||
subscription?: Json
|
||||
user_id?: string
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "subscriptions_user_id_fkey"
|
||||
columns: ["user_id"]
|
||||
isOneToOne: true
|
||||
referencedRelation: "users"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
Relationships: []
|
||||
}
|
||||
teams: {
|
||||
Row: {
|
||||
@@ -477,114 +419,19 @@ export type Database = {
|
||||
owner_id?: string | null
|
||||
ref?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "public_teams_owner_id_fkey"
|
||||
columns: ["owner_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "users"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
Relationships: []
|
||||
}
|
||||
}
|
||||
Views: {
|
||||
post_tags_with_tags: {
|
||||
category_post_count: {
|
||||
Row: {
|
||||
category_id: number | null
|
||||
category_name: string | null
|
||||
category_slug: string | null
|
||||
created_at: string | null
|
||||
id: number | null
|
||||
post_id: string | null
|
||||
tag_description: string | null
|
||||
tag_id: string | null
|
||||
tag_name: string | null
|
||||
tag_slug: string | null
|
||||
post_count: number | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_v4"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_v5"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_blog_and_subscription_status"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_blog_and_subscription_status_v2"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_tags"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_tags_v2"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "posts_with_tags_v3"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "public_posts_v2"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_post_id_fkey"
|
||||
columns: ["post_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "public_posts_v3"
|
||||
referencedColumns: ["post_id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_tag_id_fkey"
|
||||
columns: ["tag_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "blog_tags"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "post_tags_tag_id_fkey"
|
||||
columns: ["tag_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tag_usage_count_v2"
|
||||
referencedColumns: ["tag_id"]
|
||||
},
|
||||
]
|
||||
Relationships: []
|
||||
}
|
||||
posts_v4: {
|
||||
Row: {
|
||||
@@ -648,32 +495,6 @@ export type Database = {
|
||||
},
|
||||
]
|
||||
}
|
||||
posts_with_blog_and_subscription_status: {
|
||||
Row: {
|
||||
blog_id: string | null
|
||||
content: Json | null
|
||||
cover_image: string | null
|
||||
created_at: string | null
|
||||
deleted: boolean | null
|
||||
metadata: Json[] | null
|
||||
post_id: string | null
|
||||
published: boolean | null
|
||||
slug: string | null
|
||||
subscription_status: string | null
|
||||
tags: string[] | null
|
||||
title: string | null
|
||||
updated_at: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "posts_blog_id_fkey"
|
||||
columns: ["blog_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "blogs"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
posts_with_blog_and_subscription_status_v2: {
|
||||
Row: {
|
||||
blog_id: string | null
|
||||
@@ -701,143 +522,6 @@ export type Database = {
|
||||
},
|
||||
]
|
||||
}
|
||||
posts_with_tags: {
|
||||
Row: {
|
||||
blog_id: string | null
|
||||
content: Json | null
|
||||
cover_image: string | null
|
||||
created_at: string | null
|
||||
deleted: boolean | null
|
||||
metadata: Json[] | null
|
||||
post_id: string | null
|
||||
published: boolean | null
|
||||
slug: string | null
|
||||
tags: string[] | null
|
||||
title: string | null
|
||||
updated_at: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "posts_blog_id_fkey"
|
||||
columns: ["blog_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "blogs"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
posts_with_tags_v2: {
|
||||
Row: {
|
||||
blog_id: string | null
|
||||
content: Json | null
|
||||
cover_image: string | null
|
||||
created_at: string | null
|
||||
deleted: boolean | null
|
||||
metadata: Json[] | null
|
||||
post_id: string | null
|
||||
published: boolean | null
|
||||
published_at: string | null
|
||||
slug: string | null
|
||||
tags: string[] | null
|
||||
title: string | null
|
||||
updated_at: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "posts_blog_id_fkey"
|
||||
columns: ["blog_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "blogs"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
posts_with_tags_v3: {
|
||||
Row: {
|
||||
abstract: string | null
|
||||
blog_id: string | null
|
||||
content: Json | null
|
||||
cover_image: string | null
|
||||
created_at: string | null
|
||||
deleted: boolean | null
|
||||
metadata: Json[] | null
|
||||
post_id: string | null
|
||||
published: boolean | null
|
||||
published_at: string | null
|
||||
slug: string | null
|
||||
tags: string[] | null
|
||||
title: string | null
|
||||
updated_at: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "posts_blog_id_fkey"
|
||||
columns: ["blog_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "blogs"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
public_posts_v2: {
|
||||
Row: {
|
||||
blog_id: string | null
|
||||
blog_slug: string | null
|
||||
content: Json | null
|
||||
cover_image: string | null
|
||||
created_at: string | null
|
||||
deleted: boolean | null
|
||||
html_content: string | null
|
||||
metadata: Json[] | null
|
||||
post_id: string | null
|
||||
published: boolean | null
|
||||
published_at: string | null
|
||||
slug: string | null
|
||||
subscription_status: string | null
|
||||
tags: string[] | null
|
||||
title: string | null
|
||||
updated_at: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "posts_blog_id_fkey"
|
||||
columns: ["blog_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "blogs"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
public_posts_v3: {
|
||||
Row: {
|
||||
abstract: string | null
|
||||
blog_id: string | null
|
||||
blog_slug: string | null
|
||||
content: Json | null
|
||||
cover_image: string | null
|
||||
created_at: string | null
|
||||
deleted: boolean | null
|
||||
html_content: string | null
|
||||
metadata: Json[] | null
|
||||
post_id: string | null
|
||||
published: boolean | null
|
||||
published_at: string | null
|
||||
slug: string | null
|
||||
subscription_status: string | null
|
||||
tags: string[] | null
|
||||
title: string | null
|
||||
updated_at: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "posts_blog_id_fkey"
|
||||
columns: ["blog_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "blogs"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
tag_usage_count_v2: {
|
||||
Row: {
|
||||
blog_id: string | null
|
||||
@@ -879,7 +563,7 @@ export type Database = {
|
||||
}
|
||||
Returns: {
|
||||
title: string
|
||||
html_content: Json
|
||||
html_content: string
|
||||
slug: string
|
||||
category_name: string
|
||||
category_slug: string
|
||||
@@ -998,3 +682,18 @@ export type Enums<
|
||||
: PublicEnumNameOrOptions extends keyof PublicSchema["Enums"]
|
||||
? PublicSchema["Enums"][PublicEnumNameOrOptions]
|
||||
: never
|
||||
|
||||
export type CompositeTypes<
|
||||
PublicCompositeTypeNameOrOptions extends
|
||||
| keyof PublicSchema["CompositeTypes"]
|
||||
| { schema: keyof Database },
|
||||
CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
|
||||
schema: keyof Database
|
||||
}
|
||||
? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"]
|
||||
: never = never,
|
||||
> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database }
|
||||
? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName]
|
||||
: PublicCompositeTypeNameOrOptions extends keyof PublicSchema["CompositeTypes"]
|
||||
? PublicSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions]
|
||||
: never
|
||||
|
||||
Reference in New Issue
Block a user