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