Browse Source

#99

feature/099
みてるぞ 1 week ago
parent
commit
ff4b0eecf5
12 changed files with 55 additions and 63 deletions
  1. +6
    -4
      backend/app/controllers/materials_controller.rb
  2. +5
    -5
      backend/app/controllers/tags_controller.rb
  3. +2
    -0
      backend/app/models/tag.rb
  4. +9
    -8
      backend/app/representations/material_repr.rb
  5. +1
    -1
      backend/app/representations/tag_repr.rb
  6. +1
    -1
      frontend/src/App.tsx
  7. +19
    -41
      frontend/src/components/TagLink.tsx
  8. +1
    -1
      frontend/src/pages/materials/MaterialBasePage.tsx
  9. +7
    -0
      frontend/src/pages/materials/MaterialDetailPage.tsx
  10. +1
    -1
      frontend/src/pages/posts/PostDetailPage.tsx
  11. +1
    -1
      frontend/src/pages/posts/PostListPage.tsx
  12. +2
    -0
      frontend/src/types.ts

+ 6
- 4
backend/app/controllers/materials_controller.rb View File

@@ -18,7 +18,7 @@ class MaterialsController < ApplicationController
count = q.count count = q.count
materials = q.order(created_at: :desc, id: :desc).limit(limit).offset(offset) materials = q.order(created_at: :desc, id: :desc).limit(limit).offset(offset)


render json: { materials: MaterialRepr.many(materials), count: count }
render json: { materials: MaterialRepr.many(materials, host: request.base_url), count: count }
end end


def show def show
@@ -29,7 +29,9 @@ class MaterialsController < ApplicationController
.find_by(id: params[:id]) .find_by(id: params[:id])
return head :not_found unless material return head :not_found unless material


render json: MaterialRepr.base(material)
wiki_page_body = material.tag.tag_name.wiki_page&.current_revision&.body

render json: MaterialRepr.base(material, host: request.base_url).merge(wiki_page_body:)
end end


def create def create
@@ -50,7 +52,7 @@ class MaterialsController < ApplicationController
material.file.attach(file) material.file.attach(file)


if material.save if material.save
render json: MaterialRepr.base(material), status: :created
render json: MaterialRepr.base(material, host: request.base_url), status: :created
else else
render json: { errors: material.errors.full_messages }, status: :unprocessable_entity render json: { errors: material.errors.full_messages }, status: :unprocessable_entity
end end
@@ -80,7 +82,7 @@ class MaterialsController < ApplicationController
end end


if material.save if material.save
render json: MaterialRepr.base(material)
render json: MaterialRepr.base(material, host: request.base_url)
else else
render json: { errors: material.errors.full_messages }, status: :unprocessable_entity render json: { errors: material.errors.full_messages }, status: :unprocessable_entity
end end


+ 5
- 5
backend/app/controllers/tags_controller.rb View File

@@ -33,7 +33,7 @@ class TagsController < ApplicationController
else else
Tag.joins(:tag_name) Tag.joins(:tag_name)
end end
.includes(:tag_name, tag_name: :wiki_page)
.includes(:tag_name, tag_name: :wiki_page, :materials)
q = q.where(posts: { id: post_id }) if post_id.present? q = q.where(posts: { id: post_id }) if post_id.present?


q = q.where('tag_names.name LIKE ?', "%#{ name }%") if name q = q.where('tag_names.name LIKE ?', "%#{ name }%") if name
@@ -83,7 +83,7 @@ class TagsController < ApplicationController
tags = tags =
Tag Tag
.joins(:tag_name) .joins(:tag_name)
.includes(:tag_name, tag_name: :wiki_page)
.includes(:tag_name, tag_name: :wiki_page, :materials)
.where(category: [:meme, :character, :material]) .where(category: [:meme, :character, :material])
.where(id: tag_ids) .where(id: tag_ids)
.order('tag_names.name') .order('tag_names.name')
@@ -128,7 +128,7 @@ class TagsController < ApplicationController
end end


base = Tag.joins(:tag_name) base = Tag.joins(:tag_name)
.includes(:tag_name, tag_name: :wiki_page)
.includes(:tag_name, tag_name: :wiki_page, :materials)
base = base.where('tags.post_count > 0') if present_only base = base.where('tags.post_count > 0') if present_only


canonical_hit = canonical_hit =
@@ -153,7 +153,7 @@ class TagsController < ApplicationController


def show def show
tag = Tag.joins(:tag_name) tag = Tag.joins(:tag_name)
.includes(:tag_name, tag_name: :wiki_page)
.includes(:tag_name, tag_name: :wiki_page, :materials)
.find_by(id: params[:id]) .find_by(id: params[:id])
if tag if tag
render json: TagRepr.base(tag) render json: TagRepr.base(tag)
@@ -167,7 +167,7 @@ class TagsController < ApplicationController
return head :bad_request if name.blank? return head :bad_request if name.blank?


tag = Tag.joins(:tag_name) tag = Tag.joins(:tag_name)
.includes(:tag_name, tag_name: :wiki_page)
.includes(:tag_name, tag_name: :wiki_page, :materials)
.find_by(tag_names: { name: }) .find_by(tag_names: { name: })
if tag if tag
render json: TagRepr.base(tag) render json: TagRepr.base(tag)


+ 2
- 0
backend/app/models/tag.rb View File

@@ -73,6 +73,8 @@ class Tag < ApplicationRecord


def has_wiki = wiki_page.present? def has_wiki = wiki_page.present?


def material_id = materials.first&.id

def self.tagme def self.tagme
@tagme ||= find_or_create_by_tag_name!('タグ希望', category: :meta) @tagme ||= find_or_create_by_tag_name!('タグ希望', category: :meta)
end end


+ 9
- 8
backend/app/representations/material_repr.rb View File

@@ -2,22 +2,23 @@




module MaterialRepr module MaterialRepr
BASE = { methods: [:content_type],
include: { created_by_user: UserRepr::BASE,
BASE = { only: [:id, :url, :created_at, :updated_at],
methods: [:content_type],
include: { tag: TagRepr::BASE,
created_by_user: UserRepr::BASE,
updated_by_user: UserRepr::BASE } }.freeze updated_by_user: UserRepr::BASE } }.freeze


module_function module_function


def base(material)
def base material, host:
material.as_json(BASE).merge( material.as_json(BASE).merge(
file: if material.file.attached? file: if material.file.attached?
Rails.application.routes.url_helpers.rails_storage_proxy_url( Rails.application.routes.url_helpers.rails_storage_proxy_url(
material.file, only_path: false)
end,
tag: TagRepr.base(material.tag))
material.file, host:)
end)
end end


def many(materials)
materials.map { |m| base(m) }
def many materials, host:
materials.map { |m| base(m, host) }
end end
end end

+ 1
- 1
backend/app/representations/tag_repr.rb View File

@@ -3,7 +3,7 @@


module TagRepr module TagRepr
BASE = { only: [:id, :category, :post_count, :created_at, :updated_at], BASE = { only: [:id, :category, :post_count, :created_at, :updated_at],
methods: [:name, :has_wiki] }.freeze
methods: [:name, :has_wiki, :material_id] }.freeze


module_function module_function




+ 1
- 1
frontend/src/App.tsx View File

@@ -131,7 +131,7 @@ export default (() => {
<> <>
<RouteBlockerOverlay/> <RouteBlockerOverlay/>
<BrowserRouter> <BrowserRouter>
<div className="flex flex-col h-screen w-screen">
<div className="flex flex-col h-dvh w-screen">
<TopNav user={user}/> <TopNav user={user}/>
<RouteTransitionWrapper user={user} setUser={setUser}/> <RouteTransitionWrapper user={user} setUser={setUser}/>
</div> </div>


+ 19
- 41
frontend/src/components/TagLink.tsx View File

@@ -1,8 +1,5 @@
import { useEffect, useState } from 'react'

import PrefetchLink from '@/components/PrefetchLink' import PrefetchLink from '@/components/PrefetchLink'
import { LIGHT_COLOUR_SHADE, DARK_COLOUR_SHADE, TAG_COLOUR } from '@/consts' import { LIGHT_COLOUR_SHADE, DARK_COLOUR_SHADE, TAG_COLOUR } from '@/consts'
import { apiGet } from '@/lib/api'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'


import type { ComponentProps, FC, HTMLAttributes } from 'react' import type { ComponentProps, FC, HTMLAttributes } from 'react'
@@ -36,35 +33,6 @@ export default (({ tag,
withWiki = true, withWiki = true,
withCount = true, withCount = true,
...props }: Props) => { ...props }: Props) => {
const [havingWiki, setHavingWiki] = useState (true)

const wikiExists = async (tag: Tag) => {
if ('hasWiki' in tag)
{
setHavingWiki (tag.hasWiki)
return
}

const tagName = (tag as Tag).name

try
{
await apiGet (`/wiki/title/${ encodeURIComponent (tagName) }/exists`)
setHavingWiki (true)
}
catch
{
setHavingWiki (false)
}
}

useEffect (() => {
if (!(linkFlg) || !(withWiki))
return

wikiExists (tag)
}, [tag.name, linkFlg, withWiki])

const spanClass = cn ( const spanClass = cn (
`text-${ TAG_COLOUR[tag.category] }-${ LIGHT_COLOUR_SHADE }`, `text-${ TAG_COLOUR[tag.category] }-${ LIGHT_COLOUR_SHADE }`,
`dark:text-${ TAG_COLOUR[tag.category] }-${ DARK_COLOUR_SHADE }`) `dark:text-${ TAG_COLOUR[tag.category] }-${ DARK_COLOUR_SHADE }`)
@@ -77,17 +45,27 @@ export default (({ tag,
<> <>
{(linkFlg && withWiki) && ( {(linkFlg && withWiki) && (
<span className="mr-1"> <span className="mr-1">
{havingWiki
{(tag.materialId != null || tag.hasWiki)
? ( ? (
<PrefetchLink to={`/wiki/${ encodeURIComponent (tag.name) }`}
className={linkClass}>
?
</PrefetchLink>)
tag.materialId == null
? (
<PrefetchLink
to={`/wiki/${ encodeURIComponent (tag.name) }`}
className={linkClass}>
?
</PrefetchLink>)
: (
<PrefetchLink
to={`/materials/${ tag.materialId }`}
className={linkClass}>
?
</PrefetchLink>))
: ( : (
<PrefetchLink to={`/wiki/${ encodeURIComponent (tag.name) }`}
className="animate-[wiki-blink_.25s_steps(2,end)_infinite]
dark:animate-[wiki-blink-dark_.25s_steps(2,end)_infinite]"
title={`${ tag.name } Wiki が存在しません.`}>
<PrefetchLink
to={`/wiki/${ encodeURIComponent (tag.name) }`}
className="animate-[wiki-blink_.25s_steps(2,end)_infinite]
dark:animate-[wiki-blink-dark_.25s_steps(2,end)_infinite]"
title={`${ tag.name } Wiki が存在しません.`}>
! !
</PrefetchLink>)} </PrefetchLink>)}
</span>)} </span>)}


+ 1
- 1
frontend/src/pages/materials/MaterialBasePage.tsx View File

@@ -6,7 +6,7 @@ import type { FC } from 'react'




export default (() => ( export default (() => (
<div className="md:flex md:flex-1">
<div className="md:flex md:flex-1 md:h-[calc(100dvh-88px)]">
<MaterialSidebar/> <MaterialSidebar/>
<Outlet/> <Outlet/>
</div>)) satisfies FC </div>)) satisfies FC

+ 7
- 0
frontend/src/pages/materials/MaterialDetailPage.tsx View File

@@ -3,6 +3,7 @@ import { Helmet } from 'react-helmet-async'
import { useParams } from 'react-router-dom' import { useParams } from 'react-router-dom'


import TagLink from '@/components/TagLink' import TagLink from '@/components/TagLink'
import WikiBody from '@/components/WikiBody'
import Label from '@/components/common/Label' import Label from '@/components/common/Label'
import PageTitle from '@/components/common/PageTitle' import PageTitle from '@/components/common/PageTitle'
import TabGroup, { Tab } from '@/components/common/TabGroup' import TabGroup, { Tab } from '@/components/common/TabGroup'
@@ -109,6 +110,12 @@ export default (() => {
<audio src={material.file} controls/>)))} <audio src={material.file} controls/>)))}


<TabGroup> <TabGroup>
<Tab name="Wiki">
<WikiBody
title={material.tag.name}
body={material.wikiPageBody ?? undefined}/>
</Tab>

<Tab name="編輯"> <Tab name="編輯">
<div className="max-w-wl pt-2 space-y-4"> <div className="max-w-wl pt-2 space-y-4">
{/* タグ */} {/* タグ */}


+ 1
- 1
frontend/src/pages/posts/PostDetailPage.tsx View File

@@ -93,7 +93,7 @@ export default (({ user }: Props) => {
: 'bg-gray-500 hover:bg-gray-600') : 'bg-gray-500 hover:bg-gray-600')


return ( return (
<div className="md:flex md:flex-1">
<div className="md:flex md:flex-1 md:h-[calc(100dvh-88px)]">
<Helmet> <Helmet>
{(post?.thumbnail || post?.thumbnailBase) && ( {(post?.thumbnail || post?.thumbnailBase) && (
<meta name="thumbnail" content={post.thumbnail || post.thumbnailBase}/>)} <meta name="thumbnail" content={post.thumbnail || post.thumbnailBase}/>)}


+ 1
- 1
frontend/src/pages/posts/PostListPage.tsx View File

@@ -69,7 +69,7 @@ export default (() => {
}, [location.search]) }, [location.search])


return ( return (
<div className="md:flex md:flex-1" ref={containerRef}>
<div className="md:flex md:flex-1 md:h-[calc(100dvh-88px)]" ref={containerRef}>
<Helmet> <Helmet>
<title> <title>
{tags.length {tags.length


+ 2
- 0
frontend/src/types.ts View File

@@ -54,6 +54,7 @@ export type Material = {
tag: Tag tag: Tag
file: string | null file: string | null
url: string | null url: string | null
wikiPageBody?: string | null
contentType: string | null contentType: string | null
createdAt: string createdAt: string
createdByUser: { id: number; name: string } createdByUser: { id: number; name: string }
@@ -140,6 +141,7 @@ export type Tag = {
createdAt: string createdAt: string
updatedAt: string updatedAt: string
hasWiki: boolean hasWiki: boolean
materialId: number
children?: Tag[] children?: Tag[]
matchedAlias?: string | null } matchedAlias?: string | null }




Loading…
Cancel
Save