This commit is contained in:
@@ -100,23 +100,16 @@ class PostsController < ApplicationController
|
|||||||
.first
|
.first
|
||||||
return head :not_found unless post
|
return head :not_found unless post
|
||||||
|
|
||||||
viewed = current_user&.viewed?(post) || false
|
render json: PostRepr.base(post, current_user)
|
||||||
|
|
||||||
render json: PostRepr.base(post).merge(viewed:)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
post = Post.includes(tags: { tag_name: :wiki_page }).find_by(id: params[:id])
|
post = Post.includes(tags: { tag_name: :wiki_page }).find_by(id: params[:id])
|
||||||
return head :not_found unless post
|
return head :not_found unless post
|
||||||
|
|
||||||
viewed = current_user&.viewed?(post) || false
|
render json: PostRepr.base(post, current_user)
|
||||||
|
.merge(tags: build_tag_tree_for(post.tags),
|
||||||
json = post.as_json
|
related: post.related(limit: 20))
|
||||||
json['tags'] = build_tag_tree_for(post.tags)
|
|
||||||
json['related'] = post.related(limit: 20)
|
|
||||||
json['viewed'] = viewed
|
|
||||||
|
|
||||||
render json:
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|||||||
@@ -2,15 +2,19 @@
|
|||||||
|
|
||||||
|
|
||||||
module PostRepr
|
module PostRepr
|
||||||
BASE = { include: { tags: TagRepr::BASE } }.freeze
|
BASE = { include: { tags: TagRepr::BASE, uploaded_user: UserRepr::BASE } }.freeze
|
||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
def base post
|
def base post, current_user = nil
|
||||||
post.as_json(BASE)
|
json = post.as_json(BASE)
|
||||||
|
return json unless current_user
|
||||||
|
|
||||||
|
viewed = current_user.viewed?(post)
|
||||||
|
json.merge(viewed:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def many posts
|
def many posts, current_user = nil
|
||||||
posts.map { |p| base(p) }
|
posts.map { |p| base(p, current_user) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
|
||||||
|
module UserRepr
|
||||||
|
BASE = { only: [:id, :name] }.freeze
|
||||||
|
|
||||||
|
module_function
|
||||||
|
|
||||||
|
def base user
|
||||||
|
user.as_json(BASE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def many users
|
||||||
|
users.map { |u| base(u) }
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useDraggable, useDroppable } from '@dnd-kit/core'
|
import { useDraggable, useDroppable } from '@dnd-kit/core'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
|
||||||
import TagLink from '@/components/TagLink'
|
import TagLink from '@/components/TagLink'
|
||||||
@@ -14,10 +15,11 @@ type Props = {
|
|||||||
nestLevel: number
|
nestLevel: number
|
||||||
pathKey: string
|
pathKey: string
|
||||||
parentTagId?: number
|
parentTagId?: number
|
||||||
suppressClickRef: MutableRefObject<boolean> }
|
suppressClickRef: MutableRefObject<boolean>
|
||||||
|
sp?: boolean }
|
||||||
|
|
||||||
|
|
||||||
export default (({ tag, nestLevel, pathKey, parentTagId, suppressClickRef }: Props) => {
|
export default (({ tag, nestLevel, pathKey, parentTagId, suppressClickRef, sp }: Props) => {
|
||||||
const dndId = `tag-node:${ pathKey }`
|
const dndId = `tag-node:${ pathKey }`
|
||||||
|
|
||||||
const downPosRef = useRef<{ x: number; y: number } | null> (null)
|
const downPosRef = useRef<{ x: number; y: number } | null> (null)
|
||||||
@@ -88,6 +90,8 @@ export default (({ tag, nestLevel, pathKey, parentTagId, suppressClickRef }: Pro
|
|||||||
className={cn ('rounded select-none', over && 'ring-2 ring-offset-2')}
|
className={cn ('rounded select-none', over && 'ring-2 ring-offset-2')}
|
||||||
{...attributes}
|
{...attributes}
|
||||||
{...listeners}>
|
{...listeners}>
|
||||||
|
<motion.div layoutId={`tag-${ sp ? 'sp-' : '' }${ tag.id }`}>
|
||||||
<TagLink tag={tag} nestLevel={nestLevel}/>
|
<TagLink tag={tag} nestLevel={nestLevel}/>
|
||||||
|
</motion.div>
|
||||||
</div>)
|
</div>)
|
||||||
}) satisfies FC<Props>
|
}) satisfies FC<Props>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { DndContext,
|
|||||||
useSensor,
|
useSensor,
|
||||||
useSensors } from '@dnd-kit/core'
|
useSensors } from '@dnd-kit/core'
|
||||||
import { restrictToWindowEdges } from '@dnd-kit/modifiers'
|
import { restrictToWindowEdges } from '@dnd-kit/modifiers'
|
||||||
import { AnimatePresence, motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
|
||||||
import DraggableDroppableTagRow from '@/components/DraggableDroppableTagRow'
|
import DraggableDroppableTagRow from '@/components/DraggableDroppableTagRow'
|
||||||
import PrefetchLink from '@/components/PrefetchLink'
|
import PrefetchLink from '@/components/PrefetchLink'
|
||||||
@@ -35,28 +35,27 @@ const renderTagTree = (
|
|||||||
path: string,
|
path: string,
|
||||||
suppressClickRef: MutableRefObject<boolean>,
|
suppressClickRef: MutableRefObject<boolean>,
|
||||||
parentTagId?: number,
|
parentTagId?: number,
|
||||||
|
sp?: boolean,
|
||||||
): ReactNode[] => {
|
): ReactNode[] => {
|
||||||
const key = `${ path }-${ tag.id }`
|
const key = `${ path }-${ tag.id }`
|
||||||
|
|
||||||
const self = (
|
const self = (
|
||||||
<motion.li
|
<li key={key} className="mb-1">
|
||||||
key={key}
|
|
||||||
layout
|
|
||||||
transition={{ duration: .2, ease: 'easeOut' }}
|
|
||||||
className="mb-1">
|
|
||||||
<DraggableDroppableTagRow
|
<DraggableDroppableTagRow
|
||||||
tag={tag}
|
tag={tag}
|
||||||
nestLevel={nestLevel}
|
nestLevel={nestLevel}
|
||||||
pathKey={key}
|
pathKey={key}
|
||||||
parentTagId={parentTagId}
|
parentTagId={parentTagId}
|
||||||
suppressClickRef={suppressClickRef}/>
|
suppressClickRef={suppressClickRef}
|
||||||
</motion.li>)
|
sp={sp}/>
|
||||||
|
</li>)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
self,
|
self,
|
||||||
...((tag.children
|
...((tag.children
|
||||||
?.sort ((a, b) => a.name < b.name ? -1 : 1)
|
?.sort ((a, b) => a.name < b.name ? -1 : 1)
|
||||||
.flatMap (child => renderTagTree (child, nestLevel + 1, key, suppressClickRef, tag.id)))
|
.flatMap (child =>
|
||||||
|
renderTagTree (child, nestLevel + 1, key, suppressClickRef, tag.id, sp)))
|
||||||
?? [])]
|
?? [])]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,14 +146,32 @@ const DropSlot = ({ cat }: { cat: Category }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Props = { post: Post | null }
|
type Props = { post: Post; sp?: boolean }
|
||||||
|
|
||||||
|
|
||||||
export default (({ post }: Props) => {
|
export default (({ post, sp }: Props) => {
|
||||||
|
sp = Boolean (sp)
|
||||||
|
|
||||||
|
const baseTags = useMemo<TagByCategory> (() => {
|
||||||
|
const tagsTmp = { } as TagByCategory
|
||||||
|
|
||||||
|
for (const tag of post.tags)
|
||||||
|
{
|
||||||
|
if (!(tag.category in tagsTmp))
|
||||||
|
tagsTmp[tag.category] = []
|
||||||
|
tagsTmp[tag.category].push (tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const cat of Object.keys (tagsTmp) as (keyof typeof tagsTmp)[])
|
||||||
|
tagsTmp[cat].sort ((tagA: Tag, tagB: Tag) => tagA.name < tagB.name ? -1 : 1)
|
||||||
|
|
||||||
|
return tagsTmp
|
||||||
|
}, [post])
|
||||||
|
|
||||||
const [activeTagId, setActiveTagId] = useState<number | null> (null)
|
const [activeTagId, setActiveTagId] = useState<number | null> (null)
|
||||||
const [dragging, setDragging] = useState (false)
|
const [dragging, setDragging] = useState (false)
|
||||||
const [saving, setSaving] = useState (false)
|
const [saving, setSaving] = useState (false)
|
||||||
const [tags, setTags] = useState ({ } as TagByCategory)
|
const [tags, setTags] = useState (baseTags)
|
||||||
|
|
||||||
const suppressClickRef = useRef (false)
|
const suppressClickRef = useRef (false)
|
||||||
|
|
||||||
@@ -163,9 +180,6 @@ export default (({ post }: Props) => {
|
|||||||
useSensor (TouchSensor, { activationConstraint: { delay: 250, tolerance: 8 } }))
|
useSensor (TouchSensor, { activationConstraint: { delay: 250, tolerance: 8 } }))
|
||||||
|
|
||||||
const reloadTags = async (): Promise<void> => {
|
const reloadTags = async (): Promise<void> => {
|
||||||
if (!(post))
|
|
||||||
return
|
|
||||||
|
|
||||||
setTags (buildTagByCategory (await apiGet<Post> (`/posts/${ post.id }`)))
|
setTags (buildTagByCategory (await apiGet<Post> (`/posts/${ post.id }`)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,23 +270,8 @@ export default (({ post }: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect (() => {
|
useEffect (() => {
|
||||||
if (!(post))
|
setTags (baseTags)
|
||||||
return
|
}, [baseTags])
|
||||||
|
|
||||||
const tagsTmp = { } as TagByCategory
|
|
||||||
|
|
||||||
for (const tag of post.tags)
|
|
||||||
{
|
|
||||||
if (!(tag.category in tagsTmp))
|
|
||||||
tagsTmp[tag.category] = []
|
|
||||||
tagsTmp[tag.category].push (tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const cat of Object.keys (tagsTmp) as (keyof typeof tagsTmp)[])
|
|
||||||
tagsTmp[cat].sort ((tagA: Tag, tagB: Tag) => tagA.name < tagB.name ? -1 : 1)
|
|
||||||
|
|
||||||
setTags (tagsTmp)
|
|
||||||
}, [post])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarComponent>
|
<SidebarComponent>
|
||||||
@@ -305,26 +304,25 @@ export default (({ post }: Props) => {
|
|||||||
document.body.style.userSelect = ''
|
document.body.style.userSelect = ''
|
||||||
}}
|
}}
|
||||||
modifiers={[restrictToWindowEdges]}>
|
modifiers={[restrictToWindowEdges]}>
|
||||||
<motion.div key={post?.id ?? 0} layout>
|
|
||||||
{CATEGORIES.map ((cat: Category) => ((tags[cat] ?? []).length > 0 || dragging) && (
|
{CATEGORIES.map ((cat: Category) => ((tags[cat] ?? []).length > 0 || dragging) && (
|
||||||
<motion.div layout className="my-3" key={cat}>
|
<div className="my-3" key={cat}>
|
||||||
<SubsectionTitle>{CATEGORY_NAMES[cat]}</SubsectionTitle>
|
<SubsectionTitle>
|
||||||
|
<motion.div layoutId={`tag-${ sp ? 'sp-' : '' }${ cat }`}>
|
||||||
|
{CATEGORY_NAMES[cat]}
|
||||||
|
</motion.div>
|
||||||
|
</SubsectionTitle>
|
||||||
|
|
||||||
<motion.ul layout>
|
<ul>
|
||||||
<AnimatePresence initial={false}>
|
|
||||||
{(tags[cat] ?? []).flatMap (tag => (
|
{(tags[cat] ?? []).flatMap (tag => (
|
||||||
renderTagTree (tag, 0, `cat-${ cat }`, suppressClickRef, undefined)))}
|
renderTagTree (tag, 0, `cat-${ cat }`, suppressClickRef, undefined, sp)))}
|
||||||
<DropSlot cat={cat}/>
|
<DropSlot cat={cat}/>
|
||||||
</AnimatePresence>
|
</ul>
|
||||||
</motion.ul>
|
</div>))}
|
||||||
</motion.div>))}
|
|
||||||
{post && (
|
{post && (
|
||||||
<div>
|
<motion.div layoutId={`post-info-${ sp }`}>
|
||||||
<SectionTitle>情報</SectionTitle>
|
<SectionTitle>情報</SectionTitle>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Id.: {post.id}</li>
|
<li>Id.: {post.id}</li>
|
||||||
{/* TODO: uploadedUser の取得を対応したらコメント外す */}
|
|
||||||
{/*
|
|
||||||
<li>
|
<li>
|
||||||
<>耕作者: </>
|
<>耕作者: </>
|
||||||
{post.uploadedUser
|
{post.uploadedUser
|
||||||
@@ -334,7 +332,6 @@ export default (({ post }: Props) => {
|
|||||||
</PrefetchLink>)
|
</PrefetchLink>)
|
||||||
: 'bot操作'}
|
: 'bot操作'}
|
||||||
</li>
|
</li>
|
||||||
*/}
|
|
||||||
<li>耕作日時: {dateString (post.createdAt)}</li>
|
<li>耕作日時: {dateString (post.createdAt)}</li>
|
||||||
<li>
|
<li>
|
||||||
<>リンク: </>
|
<>リンク: </>
|
||||||
@@ -357,8 +354,7 @@ export default (({ post }: Props) => {
|
|||||||
</PrefetchLink>
|
</PrefetchLink>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>)}
|
</motion.div>)}
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
<DragOverlay adjustScale={false}>
|
<DragOverlay adjustScale={false}>
|
||||||
<div className="pointer-events-none">
|
<div className="pointer-events-none">
|
||||||
|
|||||||
@@ -65,11 +65,12 @@ export default (({ posts, onClick }: Props) => {
|
|||||||
{CATEGORIES.flatMap (cat => cat in tags ? (
|
{CATEGORIES.flatMap (cat => cat in tags ? (
|
||||||
tags[cat].map (tag => (
|
tags[cat].map (tag => (
|
||||||
<li key={tag.id} className="mb-1">
|
<li key={tag.id} className="mb-1">
|
||||||
|
<motion.div layoutId={`tag-${ tag.id }`}>
|
||||||
<TagLink tag={tag} prefetch onClick={onClick}/>
|
<TagLink tag={tag} prefetch onClick={onClick}/>
|
||||||
|
</motion.div>
|
||||||
</li>))) : [])}
|
</li>))) : [])}
|
||||||
</ul>
|
</ul>
|
||||||
<SectionTitle>関聯</SectionTitle>
|
<SectionTitle>関聯</SectionTitle>
|
||||||
{posts.length > 0 && (
|
|
||||||
<a href="#"
|
<a href="#"
|
||||||
onClick={ev => {
|
onClick={ev => {
|
||||||
ev.preventDefault ()
|
ev.preventDefault ()
|
||||||
@@ -88,7 +89,7 @@ export default (({ posts, onClick }: Props) => {
|
|||||||
}) ())
|
}) ())
|
||||||
}}>
|
}}>
|
||||||
ランダム
|
ランダム
|
||||||
</a>)}
|
</a>
|
||||||
</>)
|
</>)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -96,7 +97,7 @@ export default (({ posts, onClick }: Props) => {
|
|||||||
<TagSearch/>
|
<TagSearch/>
|
||||||
|
|
||||||
<div className="hidden md:block mt-4">
|
<div className="hidden md:block mt-4">
|
||||||
{TagBlock}
|
{posts.length > 0 && TagBlock}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AnimatePresence initial={false}>
|
<AnimatePresence initial={false}>
|
||||||
@@ -112,7 +113,7 @@ export default (({ posts, onClick }: Props) => {
|
|||||||
animate="visible"
|
animate="visible"
|
||||||
exit="hidden"
|
exit="hidden"
|
||||||
transition={{ duration: .2, ease: 'easeOut' }}>
|
transition={{ duration: .2, ease: 'easeOut' }}>
|
||||||
{TagBlock}
|
{posts.length > 0 && TagBlock}
|
||||||
</motion.div>)}
|
</motion.div>)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const getPages = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default (({ page, totalPages, siblingCount = 2 }) => {
|
export default (({ page, totalPages, siblingCount = 3 }) => {
|
||||||
const location = useLocation ()
|
const location = useLocation ()
|
||||||
|
|
||||||
const buildTo = (p: number) => {
|
const buildTo = (p: number) => {
|
||||||
@@ -64,30 +64,64 @@ export default (({ page, totalPages, siblingCount = 2 }) => {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{(page > 1)
|
{(page > 1)
|
||||||
? (
|
? (
|
||||||
|
<>
|
||||||
|
<PrefetchLink
|
||||||
|
className="md:hidden p-2"
|
||||||
|
to={buildTo (1)}
|
||||||
|
aria-label="最初のページ">
|
||||||
|
|<
|
||||||
|
</PrefetchLink>
|
||||||
<PrefetchLink
|
<PrefetchLink
|
||||||
className="p-2"
|
className="p-2"
|
||||||
to={buildTo (page - 1)}
|
to={buildTo (page - 1)}
|
||||||
aria-label="前のページ">
|
aria-label="前のページ">
|
||||||
<
|
<
|
||||||
</PrefetchLink>)
|
</PrefetchLink>
|
||||||
: <span className="p-2" aria-hidden><</span>}
|
</>)
|
||||||
|
: (
|
||||||
|
<>
|
||||||
|
<span className="md:hidden p-2" aria-hidden>
|
||||||
|
|<
|
||||||
|
</span>
|
||||||
|
<span className="p-2" aria-hidden>
|
||||||
|
<
|
||||||
|
</span>
|
||||||
|
</>)}
|
||||||
|
|
||||||
{pages.map ((p, idx) => (
|
{pages.map ((p, idx) => (
|
||||||
(p === '…')
|
(p === '…')
|
||||||
? <span key={`dots-${ idx }`} className="p-2">…</span>
|
? <span key={`dots-${ idx }`} className="hidden md:block p-2">…</span>
|
||||||
: ((p === page)
|
: ((p === page)
|
||||||
? <span key={p} className="font-bold p-2" aria-current="page">{p}</span>
|
? <span key={p} className="font-bold p-2" aria-current="page">{p}</span>
|
||||||
: <PrefetchLink key={p} className="p-2" to={buildTo (p)}>{p}</PrefetchLink>)))}
|
: (
|
||||||
|
<PrefetchLink
|
||||||
|
key={p}
|
||||||
|
className="hidden md:block p-2"
|
||||||
|
to={buildTo (p)}>
|
||||||
|
{p}
|
||||||
|
</PrefetchLink>))))}
|
||||||
|
|
||||||
{(page < totalPages)
|
{(page < totalPages)
|
||||||
? (
|
? (
|
||||||
|
<>
|
||||||
<PrefetchLink
|
<PrefetchLink
|
||||||
className="p-2"
|
className="p-2"
|
||||||
to={buildTo (page + 1)}
|
to={buildTo (page + 1)}
|
||||||
aria-label="次のページ">
|
aria-label="次のページ">
|
||||||
>
|
>
|
||||||
</PrefetchLink>)
|
</PrefetchLink>
|
||||||
: <span className="p-2" aria-hidden>></span>}
|
<PrefetchLink
|
||||||
|
className="md:hidden p-2"
|
||||||
|
to={buildTo (totalPages)}
|
||||||
|
aria-label="最後のページ">
|
||||||
|
>|
|
||||||
|
</PrefetchLink>
|
||||||
|
</>)
|
||||||
|
: (
|
||||||
|
<>
|
||||||
|
<span className="p-2" aria-hidden>></span>
|
||||||
|
<span className="md:hidden p-2" aria-hidden>>|</span>
|
||||||
|
</>)}
|
||||||
</div>
|
</div>
|
||||||
</nav>)
|
</nav>)
|
||||||
}) satisfies FC<Props>
|
}) satisfies FC<Props>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export default (({ user }: Props) => {
|
|||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
<div className="hidden md:block">
|
<div className="hidden md:block">
|
||||||
<TagDetailSidebar post={post ?? null}/>
|
{post && <TagDetailSidebar post={post}/>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MainArea className="relative">
|
<MainArea className="relative">
|
||||||
@@ -149,7 +149,7 @@ export default (({ user }: Props) => {
|
|||||||
</MainArea>
|
</MainArea>
|
||||||
|
|
||||||
<div className="md:hidden">
|
<div className="md:hidden">
|
||||||
<TagDetailSidebar post={post ?? null}/>
|
{post && <TagDetailSidebar post={post} sp/>}
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
}) satisfies FC<Props>
|
}) satisfies FC<Props>
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ export default (() => {
|
|||||||
const qName = query.get ('name') ?? ''
|
const qName = query.get ('name') ?? ''
|
||||||
const qCategory = (query.get ('category') || null) as Category | null
|
const qCategory = (query.get ('category') || null) as Category | null
|
||||||
const qPostCountGTE = Number (query.get ('post_count_gte') ?? 1)
|
const qPostCountGTE = Number (query.get ('post_count_gte') ?? 1)
|
||||||
const qPostCountLTE =
|
const qPostCountLTERaw = query.get ('post_count_lte')
|
||||||
query.get ('post_count_lte') ? Number (query.get ('post_count_lte')) : null
|
const qPostCountLTE = qPostCountLTERaw ? Number (qPostCountLTERaw) : null
|
||||||
const qCreatedFrom = query.get ('created_from') ?? ''
|
const qCreatedFrom = query.get ('created_from') ?? ''
|
||||||
const qCreatedTo = query.get ('created_to') ?? ''
|
const qCreatedTo = query.get ('created_to') ?? ''
|
||||||
const qUpdatedFrom = query.get ('updated_from') ?? ''
|
const qUpdatedFrom = query.get ('updated_from') ?? ''
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ export type Post = {
|
|||||||
originalCreatedFrom: string | null
|
originalCreatedFrom: string | null
|
||||||
originalCreatedBefore: string | null
|
originalCreatedBefore: string | null
|
||||||
createdAt: string
|
createdAt: string
|
||||||
updatedAt: string }
|
updatedAt: string
|
||||||
|
uploadedUser: { id: number; name: string } | null }
|
||||||
|
|
||||||
export type PostTagChange = {
|
export type PostTagChange = {
|
||||||
post: Post
|
post: Post
|
||||||
|
|||||||
Reference in New Issue
Block a user