diff --git a/packages/backend/src/graphql/resolvers/articles.ts b/packages/backend/src/graphql/resolvers/articles.ts index beb456e..044f44f 100644 --- a/packages/backend/src/graphql/resolvers/articles.ts +++ b/packages/backend/src/graphql/resolvers/articles.ts @@ -9,10 +9,10 @@ async function enrichArticle(db: any, article: any) { if (article.author) { const authorUser = await db .select({ - first_name: users.first_name, - last_name: users.last_name, + id: users.id, + artist_name: users.artist_name, + slug: users.slug, avatar: users.avatar, - description: users.description, }) .from(users) .where(eq(users.id, article.author)) @@ -132,6 +132,7 @@ builder.mutationField("updateArticle", (t) => excerpt: t.arg.string(), content: t.arg.string(), imageId: t.arg.string(), + authorId: t.arg.string(), tags: t.arg.stringList(), category: t.arg.string(), featured: t.arg.boolean(), @@ -145,6 +146,7 @@ builder.mutationField("updateArticle", (t) => if (args.excerpt !== undefined) updates.excerpt = args.excerpt; if (args.content !== undefined) updates.content = args.content; if (args.imageId !== undefined) updates.image = args.imageId; + if (args.authorId !== undefined) updates.author = args.authorId; if (args.tags !== undefined && args.tags !== null) updates.tags = args.tags; if (args.category !== undefined) updates.category = args.category; if (args.featured !== undefined && args.featured !== null) updates.featured = args.featured; diff --git a/packages/backend/src/graphql/types/index.ts b/packages/backend/src/graphql/types/index.ts index 967e222..75a6dba 100644 --- a/packages/backend/src/graphql/types/index.ts +++ b/packages/backend/src/graphql/types/index.ts @@ -6,7 +6,6 @@ import type { Video, ModelPhoto, Model, - ArticleAuthor, Article, CommentUser, Comment, @@ -139,15 +138,6 @@ export const ModelType = builder.objectRef("Model").implement({ }), }); -export const ArticleAuthorType = builder.objectRef("ArticleAuthor").implement({ - fields: (t) => ({ - first_name: t.exposeString("first_name", { nullable: true }), - last_name: t.exposeString("last_name", { nullable: true }), - avatar: t.exposeString("avatar", { nullable: true }), - description: t.exposeString("description", { nullable: true }), - }), -}); - export const ArticleType = builder.objectRef
("Article").implement({ fields: (t) => ({ id: t.exposeString("id"), @@ -160,7 +150,7 @@ export const ArticleType = builder.objectRef
("Article").implement({ publish_date: t.expose("publish_date", { type: "DateTime" }), category: t.exposeString("category", { nullable: true }), featured: t.exposeBoolean("featured", { nullable: true }), - author: t.expose("author", { type: ArticleAuthorType, nullable: true }), + author: t.expose("author", { type: VideoModelType, nullable: true }), }), }); diff --git a/packages/frontend/src/lib/components/header/header.svelte b/packages/frontend/src/lib/components/header/header.svelte index 5972d9f..422455b 100644 --- a/packages/frontend/src/lib/components/header/header.svelte +++ b/packages/frontend/src/lib/components/header/header.svelte @@ -172,7 +172,7 @@
diff --git a/packages/frontend/src/lib/services.ts b/packages/frontend/src/lib/services.ts index 0bf3522..8832183 100644 --- a/packages/frontend/src/lib/services.ts +++ b/packages/frontend/src/lib/services.ts @@ -229,10 +229,10 @@ const ARTICLES_QUERY = gql` category featured author { - first_name - last_name + id + artist_name + slug avatar - description } } } @@ -259,10 +259,10 @@ const ARTICLE_BY_SLUG_QUERY = gql` category featured author { - first_name - last_name + id + artist_name + slug avatar - description } } } @@ -1387,8 +1387,9 @@ const ADMIN_LIST_ARTICLES_QUERY = gql` featured content author { - first_name - last_name + id + artist_name + slug avatar } } @@ -1467,6 +1468,7 @@ const UPDATE_ARTICLE_MUTATION = gql` $excerpt: String $content: String $imageId: String + $authorId: String $tags: [String!] $category: String $featured: Boolean @@ -1479,6 +1481,7 @@ const UPDATE_ARTICLE_MUTATION = gql` excerpt: $excerpt content: $content imageId: $imageId + authorId: $authorId tags: $tags category: $category featured: $featured @@ -1498,6 +1501,7 @@ export async function updateArticle(input: { excerpt?: string; content?: string; imageId?: string; + authorId?: string | null; tags?: string[]; category?: string; featured?: boolean; diff --git a/packages/frontend/src/routes/admin/articles/[id]/+page.server.ts b/packages/frontend/src/routes/admin/articles/[id]/+page.server.ts index 4ac994f..1afe111 100644 --- a/packages/frontend/src/routes/admin/articles/[id]/+page.server.ts +++ b/packages/frontend/src/routes/admin/articles/[id]/+page.server.ts @@ -1,10 +1,13 @@ -import { adminListArticles } from "$lib/services"; +import { adminListArticles, adminListUsers } from "$lib/services"; import { error } from "@sveltejs/kit"; export async function load({ params, fetch, cookies }) { const token = cookies.get("session_token") || ""; - const articles = await adminListArticles(fetch, token).catch(() => []); + const [articles, modelsResult] = await Promise.all([ + adminListArticles(fetch, token).catch(() => []), + adminListUsers({ role: "model", limit: 200 }, fetch, token).catch(() => ({ items: [], total: 0 })), + ]); const article = articles.find((a) => a.id === params.id); if (!article) throw error(404, "Article not found"); - return { article }; + return { article, authors: modelsResult.items }; } diff --git a/packages/frontend/src/routes/admin/articles/[id]/+page.svelte b/packages/frontend/src/routes/admin/articles/[id]/+page.svelte index 82e9c78..d153819 100644 --- a/packages/frontend/src/routes/admin/articles/[id]/+page.svelte +++ b/packages/frontend/src/routes/admin/articles/[id]/+page.svelte @@ -10,6 +10,7 @@ import { TagsInput } from "$lib/components/ui/tags-input"; import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone"; import { getAssetUrl } from "$lib/api"; + import { Select, SelectContent, SelectItem, SelectTrigger } from "$lib/components/ui/select"; const { data } = $props(); @@ -24,6 +25,8 @@ data.article.publish_date ? new Date(data.article.publish_date).toISOString().slice(0, 16) : "", ); let imageId = $state(data.article.image ?? null); + let authorId = $state(data.article.author?.id ?? ""); + let selectedAuthor = $derived(data.authors.find((a) => a.id === authorId) ?? null); let saving = $state(false); let editorTab = $state<"write" | "preview">("write"); @@ -53,6 +56,7 @@ excerpt: excerpt || undefined, content: content || undefined, imageId: imageId || undefined, + authorId: authorId || null, tags, category: category || undefined, featured, @@ -139,6 +143,34 @@
+ +
+ + +
+
diff --git a/packages/frontend/src/routes/admin/videos/+page.svelte b/packages/frontend/src/routes/admin/videos/+page.svelte index cd798ce..f5702e8 100644 --- a/packages/frontend/src/routes/admin/videos/+page.svelte +++ b/packages/frontend/src/routes/admin/videos/+page.svelte @@ -4,6 +4,7 @@ import { deleteVideo } from "$lib/services"; import { getAssetUrl } from "$lib/api"; import { Button } from "$lib/components/ui/button"; + import { Badge } from "$lib/components/ui/badge"; import * as Dialog from "$lib/components/ui/dialog"; import type { Video } from "$lib/types"; @@ -81,15 +82,10 @@
{#if video.premium} - Premium + Premium {/if} {#if video.featured} - Featured + Featured {/if}
diff --git a/packages/frontend/src/routes/admin/videos/[id]/+page.svelte b/packages/frontend/src/routes/admin/videos/[id]/+page.svelte index 3f9c408..046ebc5 100644 --- a/packages/frontend/src/routes/admin/videos/[id]/+page.svelte +++ b/packages/frontend/src/routes/admin/videos/[id]/+page.svelte @@ -9,6 +9,7 @@ import { TagsInput } from "$lib/components/ui/tags-input"; import { FileDropZone, MEGABYTE } from "$lib/components/ui/file-drop-zone"; import { getAssetUrl } from "$lib/api"; + import { Select, SelectContent, SelectItem, SelectTrigger } from "$lib/components/ui/select"; const { data } = $props(); @@ -56,12 +57,6 @@ } } - function toggleModel(id: string) { - selectedModelIds = selectedModelIds.includes(id) - ? selectedModelIds.filter((m) => m !== id) - : [...selectedModelIds, id]; - } - async function handleSubmit() { saving = true; try { @@ -155,23 +150,27 @@
{#if data.models.length > 0} -
+
-
- {#each data.models as model (model.id)} - - {/each} -
+
{/if} diff --git a/packages/frontend/src/routes/magazine/+page.svelte b/packages/frontend/src/routes/magazine/+page.svelte index 19833cb..313723f 100644 --- a/packages/frontend/src/routes/magazine/+page.svelte +++ b/packages/frontend/src/routes/magazine/+page.svelte @@ -27,7 +27,7 @@ const matchesSearch = article.title.toLowerCase().includes(searchQuery.toLowerCase()) || article.excerpt?.toLowerCase().includes(searchQuery.toLowerCase()) || - article.author?.first_name?.toLowerCase().includes(searchQuery.toLowerCase()); + article.author?.artist_name?.toLowerCase().includes(searchQuery.toLowerCase()); const matchesCategory = categoryFilter === "all" || article.category === categoryFilter; return matchesSearch && matchesCategory; }) @@ -190,11 +190,11 @@
{featuredArticle.author?.first_name}
-

{featuredArticle.author?.first_name}

+

{featuredArticle.author?.artist_name}

{timeAgo.format(new Date(featuredArticle.publish_date))} @@ -288,11 +288,11 @@
{article.author?.first_name}
-

{article.author?.first_name}

+

{article.author?.artist_name}

{timeAgo.format(new Date(article.publish_date))} diff --git a/packages/frontend/src/routes/magazine/[slug]/+page.svelte b/packages/frontend/src/routes/magazine/[slug]/+page.svelte index e94f8f6..5811932 100644 --- a/packages/frontend/src/routes/magazine/[slug]/+page.svelte +++ b/packages/frontend/src/routes/magazine/[slug]/+page.svelte @@ -141,32 +141,21 @@ {#if data.article.author} + {@const author = data.article.author}
{data.article.author.first_name}
-

- About {data.article.author.first_name} -

- {#if data.article.author.description} -

- {data.article.author.description} -

- {/if} - {#if data.article.author.website} - +

About {author.artist_name}

+ {#if author.slug} + + View profile + {/if}
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 7a67e1d..932dacc 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -87,14 +87,6 @@ export interface Model { // ─── Article ───────────────────────────────────────────────────────────────── -export interface ArticleAuthor { - first_name: string | null; - last_name: string | null; - avatar: string | null; - description: string | null; - website?: string | null; -} - export interface Article { id: string; slug: string; @@ -106,7 +98,7 @@ export interface Article { publish_date: Date; category: string | null; featured: boolean | null; - author?: ArticleAuthor | null; + author?: VideoModel | null; } // ─── Comment ─────────────────────────────────────────────────────────────────