@@ -20,10 +20,12 @@ import WikiHistoryPage from '@/pages/wiki/WikiHistoryPage' | |||
import WikiNewPage from '@/pages/wiki/WikiNewPage' | |||
import WikiSearchPage from '@/pages/wiki/WikiSearchPage' | |||
import type { FC } from 'react' | |||
import type { User } from '@/types' | |||
export default () => { | |||
export default (() => { | |||
const [user, setUser] = useState<User | null> (null) | |||
const [status, setStatus] = useState (200) | |||
@@ -91,4 +93,4 @@ export default () => { | |||
</div> | |||
<Toaster/> | |||
</BrowserRouter>) | |||
} | |||
}) satisfies FC |
@@ -5,10 +5,12 @@ import errorImg from '@/assets/images/not-found.gif' | |||
import MainArea from '@/components/layout/MainArea' | |||
import { SITE_TITLE } from '@/config' | |||
import type { FC } from 'react' | |||
type Props = { status: number } | |||
export default ({ status }: Props) => { | |||
export default (({ status }: Props) => { | |||
const [message, rightMsg, leftMsg]: [string, string, string] = (() => { | |||
switch (status) | |||
{ | |||
@@ -56,4 +58,4 @@ export default ({ status }: Props) => { | |||
<p className="mr-[-.5em]">{message}</p> | |||
</div> | |||
</MainArea>) | |||
} | |||
}) satisfies FC<Props> |
@@ -1,6 +1,9 @@ | |||
export default () => ( | |||
import type { FC } from 'react' | |||
export default (() => ( | |||
<> | |||
<span className="hidden md:inline flex items-center px-2">|</span> | |||
<hr className="block md:hidden w-full opacity-25 | |||
border-t border-black dark:border-white"/> | |||
</>) | |||
</>)) satisfies FC |
@@ -4,10 +4,10 @@ type Props = { id: string, | |||
height: number, | |||
style?: CSSProperties } | |||
import type { CSSProperties } from 'react' | |||
import type { CSSProperties, FC } from 'react' | |||
export default (props: Props) => { | |||
export default ((props: Props) => { | |||
const { id, width, height, style = { } } = props | |||
const iframeRef = useRef<HTMLIFrameElement> (null) | |||
@@ -108,4 +108,4 @@ export default (props: Props) => { | |||
style={margedStyle} | |||
allowFullScreen | |||
allow="autoplay"/>) | |||
} | |||
}) satisfies FC<Props> |
@@ -6,13 +6,15 @@ import TextArea from '@/components/common/TextArea' | |||
import { Button } from '@/components/ui/button' | |||
import { API_BASE_URL } from '@/config' | |||
import type { FC } from 'react' | |||
import type { Post } from '@/types' | |||
type Props = { post: Post | |||
onSave: (newPost: Post) => void } | |||
type Props = { post: Post | |||
onSave: (newPost: Post) => void } | |||
export default ({ post, onSave }: Props) => { | |||
export default (({ post, onSave }: Props) => { | |||
const [title, setTitle] = useState (post.title) | |||
const [tags, setTags] = useState<string> (post.tags | |||
.filter (t => t.category !== 'nico') | |||
@@ -55,4 +57,4 @@ export default ({ post, onSave }: Props) => { | |||
更新 | |||
</Button> | |||
</div>) | |||
} | |||
}) satisfies FC<Props> |
@@ -1,13 +1,14 @@ | |||
import { Link } from 'react-router-dom' | |||
import type { MouseEvent } from 'react' | |||
import type { FC, MouseEvent } from 'react' | |||
import type { Post } from '@/types' | |||
type Props = { posts: Post[] | |||
onClick?: (event: MouseEvent<HTMLElement>) => void } | |||
export default ({ posts, onClick }: Props) => ( | |||
export default (({ posts, onClick }: Props) => ( | |||
<div className="flex flex-wrap gap-6 p-4"> | |||
{posts.map ((post, i) => ( | |||
<Link to={`/posts/${ post.id }`} | |||
@@ -22,4 +23,4 @@ export default ({ posts, onClick }: Props) => ( | |||
decoding="async" | |||
className="object-none w-full h-full" /> | |||
</Link>))} | |||
</div>) | |||
</div>)) satisfies FC<Props> |
@@ -6,6 +6,8 @@ import SubsectionTitle from '@/components/common/SubsectionTitle' | |||
import SidebarComponent from '@/components/layout/SidebarComponent' | |||
import { CATEGORIES } from '@/consts' | |||
import type { FC } from 'react' | |||
import type { Category, Post, Tag } from '@/types' | |||
type TagByCategory = { [key in Category]: Tag[] } | |||
@@ -13,7 +15,7 @@ type TagByCategory = { [key in Category]: Tag[] } | |||
type Props = { post: Post | null } | |||
export default ({ post }: Props) => { | |||
export default (({ post }: Props) => { | |||
const [tags, setTags] = useState ({ } as TagByCategory) | |||
const categoryNames: Record<Category, string> = { | |||
@@ -58,4 +60,4 @@ export default ({ post }: Props) => { | |||
</ul> | |||
</div>))} | |||
</SidebarComponent>) | |||
} | |||
}) satisfies FC<Props> |
@@ -3,7 +3,7 @@ import { Link } from 'react-router-dom' | |||
import { LIGHT_COLOUR_SHADE, DARK_COLOUR_SHADE, TAG_COLOUR } from '@/consts' | |||
import { cn } from '@/lib/utils' | |||
import type { ComponentProps, HTMLAttributes } from 'react' | |||
import type { ComponentProps, FC, HTMLAttributes } from 'react' | |||
import type { Tag } from '@/types' | |||
@@ -20,11 +20,11 @@ type PropsWithoutLink = | |||
type Props = PropsWithLink | PropsWithoutLink | |||
export default ({ tag, | |||
linkFlg = true, | |||
withWiki = true, | |||
withCount = true, | |||
...props }: Props) => { | |||
export default (({ tag, | |||
linkFlg = true, | |||
withWiki = true, | |||
withCount = true, | |||
...props }: Props) => { | |||
const spanClass = cn ( | |||
`text-${ TAG_COLOUR[tag.category] }-${ LIGHT_COLOUR_SHADE }`, | |||
`dark:text-${ TAG_COLOUR[tag.category] }-${ DARK_COLOUR_SHADE }`) | |||
@@ -57,4 +57,4 @@ export default ({ tag, | |||
{withCount && ( | |||
<span className="ml-1">{tag.postCount}</span>)} | |||
</>) | |||
} | |||
}) satisfies FC<Props> |
@@ -6,10 +6,12 @@ import { API_BASE_URL } from '@/config' | |||
import TagSearchBox from './TagSearchBox' | |||
import type { FC } from 'react' | |||
import type { Tag } from '@/types' | |||
const TagSearch: React.FC = () => { | |||
export default (() => { | |||
const location = useLocation () | |||
const navigate = useNavigate () | |||
@@ -24,8 +26,8 @@ const TagSearch: React.FC = () => { | |||
const q = ev.target.value.trim ().split (' ').at (-1) | |||
if (!(q)) | |||
{ | |||
setSuggestions ([]) | |||
return | |||
setSuggestions ([]) | |||
return | |||
} | |||
const res = await axios.get (`${ API_BASE_URL }/tags/autocomplete`, { params: { q } }) | |||
@@ -52,7 +54,7 @@ const TagSearch: React.FC = () => { | |||
case 'Enter': | |||
if (activeIndex < 0) | |||
break | |||
break | |||
ev.preventDefault () | |||
const selected = suggestions[activeIndex] | |||
selected && handleTagSelect (selected) | |||
@@ -65,8 +67,8 @@ const TagSearch: React.FC = () => { | |||
} | |||
if (ev.key === 'Enter' && (!(suggestionsVsbl) || activeIndex < 0)) | |||
{ | |||
navigate (`/posts?${ (new URLSearchParams ({ tags: search })).toString () }`) | |||
setSuggestionsVsbl (false) | |||
navigate (`/posts?${ (new URLSearchParams ({ tags: search })).toString () }`) | |||
setSuggestionsVsbl (false) | |||
} | |||
} | |||
@@ -86,18 +88,16 @@ const TagSearch: React.FC = () => { | |||
return ( | |||
<div className="relative w-full"> | |||
<input type="text" | |||
placeholder="タグ検索..." | |||
value={search} | |||
onChange={whenChanged} | |||
onFocus={() => setSuggestionsVsbl (true)} | |||
onBlur={() => setSuggestionsVsbl (false)} | |||
onKeyDown={handleKeyDown} | |||
className="w-full px-3 py-2 border rounded dark:border-gray-600 dark:bg-gray-800 dark:text-white"/> | |||
<TagSearchBox suggestions={suggestionsVsbl && suggestions.length ? suggestions : [] as Tag[]} | |||
activeIndex={activeIndex} | |||
onSelect={handleTagSelect}/> | |||
<input type="text" | |||
placeholder="タグ検索..." | |||
value={search} | |||
onChange={whenChanged} | |||
onFocus={() => setSuggestionsVsbl (true)} | |||
onBlur={() => setSuggestionsVsbl (false)} | |||
onKeyDown={handleKeyDown} | |||
className="w-full px-3 py-2 border rounded dark:border-gray-600 dark:bg-gray-800 dark:text-white"/> | |||
<TagSearchBox suggestions={suggestionsVsbl && suggestions.length ? suggestions : [] as Tag[]} | |||
activeIndex={activeIndex} | |||
onSelect={handleTagSelect}/> | |||
</div>) | |||
} | |||
export default TagSearch | |||
}) satisfies FC |
@@ -1,5 +1,7 @@ | |||
import { cn } from '@/lib/utils' | |||
import type { FC } from 'react' | |||
import type { Tag } from '@/types' | |||
type Props = { suggestions: Tag[] | |||
@@ -7,7 +9,7 @@ type Props = { suggestions: Tag[] | |||
onSelect: (tag: Tag) => void } | |||
export default ({ suggestions, activeIndex, onSelect }: Props) => { | |||
export default (({ suggestions, activeIndex, onSelect }: Props) => { | |||
if (!(suggestions.length)) | |||
return | |||
@@ -25,4 +27,4 @@ export default ({ suggestions, activeIndex, onSelect }: Props) => { | |||
{<span className="ml-2 text-sm text-gray-400">{tag.postCount}</span>} | |||
</li>))} | |||
</ul>) | |||
} | |||
}) satisfies FC<Props> |
@@ -10,6 +10,8 @@ import { API_BASE_URL } from '@/config' | |||
import { CATEGORIES } from '@/consts' | |||
import { cn } from '@/lib/utils' | |||
import type { FC } from 'react' | |||
import type { Post, Tag } from '@/types' | |||
type TagByCategory = Record<string, Tag[]> | |||
@@ -17,7 +19,7 @@ type TagByCategory = Record<string, Tag[]> | |||
type Props = { posts: Post[] } | |||
export default ({ posts }: Props) => { | |||
export default (({ posts }: Props) => { | |||
const navigate = useNavigate () | |||
const [tagsVsbl, setTagsVsbl] = useState (false) | |||
@@ -101,4 +103,4 @@ export default ({ posts }: Props) => { | |||
{tagsVsbl ? '▲▲▲ タグ一覧を閉じる ▲▲▲' : '▼▼▼ タグ一覧を表示 ▼▼▼'} | |||
</a> | |||
</SidebarComponent>) | |||
} | |||
}) satisfies FC<Props> |
@@ -9,12 +9,14 @@ import { API_BASE_URL } from '@/config' | |||
import { WikiIdBus } from '@/lib/eventBus/WikiIdBus' | |||
import { cn } from '@/lib/utils' | |||
import type { FC } from 'react' | |||
import type { Menu, Tag, User, WikiPage } from '@/types' | |||
type Props = { user: User | null } | |||
export default ({ user }: Props) => { | |||
export default (({ user }: Props) => { | |||
const location = useLocation () | |||
const [menuOpen, setMenuOpen] = useState (false) | |||
@@ -167,4 +169,4 @@ export default ({ user }: Props) => { | |||
<Separator/> | |||
</div> | |||
</>) | |||
} | |||
}) satisfies FC<Props> |
@@ -3,13 +3,15 @@ import { Link } from 'react-router-dom' | |||
import Separator from '@/components/MenuSeparator' | |||
import { cn } from '@/lib/utils' | |||
import type { FC } from 'react' | |||
import type { User } from '@/types' | |||
type Props = { user: User | null, | |||
sp?: boolean } | |||
export default ({ user, sp }: Props) => { | |||
export default (({ user, sp }: Props) => { | |||
if (!(user)) | |||
return | |||
@@ -27,4 +29,4 @@ export default ({ user, sp }: Props) => { | |||
{user.name || '名もなきニジラー'} | |||
</Link> | |||
</>) | |||
} | |||
}) satisfies FC<Props> |
@@ -9,6 +9,7 @@ import SectionTitle from '@/components/common/SectionTitle' | |||
import SubsectionTitle from '@/components/common/SubsectionTitle' | |||
import { API_BASE_URL } from '@/config' | |||
import type { FC } from 'react' | |||
import type { Components } from 'react-markdown' | |||
import type { WikiPage } from '@/types' | |||
@@ -31,7 +32,7 @@ const mdComponents = { h1: ({ children }) => <SectionTitle>{children}</SectionT | |||
</a>))) } as const satisfies Components | |||
export default ({ title, body }: Props) => { | |||
export default (({ title, body }: Props) => { | |||
const [pageNames, setPageNames] = useState<string[]> ([]) | |||
const [realBody, setRealBody] = useState<string> ('') | |||
@@ -101,4 +102,4 @@ export default ({ title, body }: Props) => { | |||
<ReactMarkdown components={mdComponents} remarkPlugins={[remarkGFM]}> | |||
{realBody || `このページは存在しません。[新規作成してください](/wiki/new?title=${ encodeURIComponent (title) })。`} | |||
</ReactMarkdown>) | |||
} | |||
}) satisfies FC<Props> |
@@ -1,9 +1,11 @@ | |||
import React from 'react' | |||
import type { FC } from 'react' | |||
type Props = { children: React.ReactNode } | |||
export default ({ children }: Props) => ( | |||
export default (({ children }: Props) => ( | |||
<div className="max-w-xl mx-auto p-4 space-y-4"> | |||
{children} | |||
</div>) | |||
</div>)) satisfies FC<Props> |