| @@ -4,9 +4,9 @@ import TagPage from '@/pages/TagPage' | |||||
| import TopNav from '@/components/TopNav' | import TopNav from '@/components/TopNav' | ||||
| import TagSidebar from '@/components/TagSidebar' | import TagSidebar from '@/components/TagSidebar' | ||||
| import TagDetailSidebar from '@/components/TagDetailSidebar' | import TagDetailSidebar from '@/components/TagDetailSidebar' | ||||
| import PostPage from '@/pages/PostPage' | |||||
| import PostNewPage from '@/pages/PostNewPage' | |||||
| import PostDetailPage from '@/pages/PostDetailPage' | |||||
| import PostPage from '@/pages/posts/PostPage' | |||||
| import PostNewPage from '@/pages/posts/PostNewPage' | |||||
| import PostDetailPage from '@/pages/posts/PostDetailPage' | |||||
| import WikiPage from '@/pages/WikiPage' | import WikiPage from '@/pages/WikiPage' | ||||
| import WikiNewPage from '@/pages/WikiNewPage' | import WikiNewPage from '@/pages/WikiNewPage' | ||||
| import WikiEditPage from '@/pages/WikiEditPage' | import WikiEditPage from '@/pages/WikiEditPage' | ||||
| @@ -1,6 +1,7 @@ | |||||
| import React, { useEffect, useState } from 'react' | import React, { useEffect, useState } from 'react' | ||||
| import axios from 'axios' | import axios from 'axios' | ||||
| import { API_BASE_URL } from '@/config' | import { API_BASE_URL } from '@/config' | ||||
| import { Button } from '@/components/ui/button' | |||||
| import type { Post, Tag } from '@/types' | import type { Post, Tag } from '@/types' | ||||
| @@ -64,9 +65,9 @@ export default ({ post, onSave }: Props) => { | |||||
| </div> | </div> | ||||
| {/* 送信 */} | {/* 送信 */} | ||||
| <button onClick={handleSubmit} | |||||
| <Button onClick={handleSubmit} | |||||
| className="px-4 py-2 bg-blue-600 text-white rounded disabled:bg-gray-400"> | className="px-4 py-2 bg-blue-600 text-white rounded disabled:bg-gray-400"> | ||||
| 更新 | 更新 | ||||
| </button> | |||||
| </Button> | |||||
| </div>) | </div>) | ||||
| } | } | ||||
| @@ -1,9 +1,11 @@ | |||||
| import React, { useEffect, useState } from 'react' | |||||
| import axios from 'axios' | import axios from 'axios' | ||||
| import React, { useEffect, useState } from 'react' | |||||
| import { Link, useParams } from 'react-router-dom' | import { Link, useParams } from 'react-router-dom' | ||||
| import TagSearch from '@/components/TagSearch' | |||||
| import SubsectionTitle from '@/components/common/SubsectionTitle' | |||||
| import SidebarComponent from '@/components/layout/SidebarComponent' | |||||
| import { API_BASE_URL } from '@/config' | import { API_BASE_URL } from '@/config' | ||||
| import TagSearch from './TagSearch' | |||||
| import SidebarComponent from './layout/SidebarComponent' | |||||
| import { CATEGORIES } from '@/consts' | import { CATEGORIES } from '@/consts' | ||||
| import type { Category, Post, Tag } from '@/types' | import type { Category, Post, Tag } from '@/types' | ||||
| @@ -45,17 +47,16 @@ export default ({ post }: Props) => { | |||||
| <SidebarComponent> | <SidebarComponent> | ||||
| <TagSearch /> | <TagSearch /> | ||||
| {CATEGORIES.map ((cat: Category) => cat in tags && ( | {CATEGORIES.map ((cat: Category) => cat in tags && ( | ||||
| <> | |||||
| <h2>{categoryNames[cat]}</h2> | |||||
| <div className="my-3"> | |||||
| <SubsectionTitle>{categoryNames[cat]}</SubsectionTitle> | |||||
| <ul> | <ul> | ||||
| {tags[cat].map (tag => ( | {tags[cat].map (tag => ( | ||||
| <li key={tag.id} className="mb-2"> | |||||
| <Link to={`/posts?${ (new URLSearchParams ({ tags: tag.name })).toString () }`} | |||||
| className="text-blue-600 hover:underline"> | |||||
| <li key={tag.id} className="mb-1"> | |||||
| <Link to={`/posts?${ (new URLSearchParams ({ tags: tag.name })).toString () }`}> | |||||
| {tag.name} | {tag.name} | ||||
| </Link> | </Link> | ||||
| </li>))} | </li>))} | ||||
| </ul> | </ul> | ||||
| </>))} | |||||
| </div>))} | |||||
| </SidebarComponent>) | </SidebarComponent>) | ||||
| } | } | ||||
| @@ -1,7 +1,8 @@ | |||||
| import React, { useEffect, useState } from 'react' | import React, { useEffect, useState } from 'react' | ||||
| import axios from 'axios' | import axios from 'axios' | ||||
| import { Link, useNavigate, useLocation } from 'react-router-dom' | import { Link, useNavigate, useLocation } from 'react-router-dom' | ||||
| import { API_BASE_URL } from '../config' | |||||
| import { API_BASE_URL } from '@/config' | |||||
| import { cn } from '@/lib/utils' | |||||
| import type { Tag } from '@/types' | import type { Tag } from '@/types' | ||||
| @@ -23,8 +24,10 @@ const TagSearchBox: React.FC = (props: Props) => { | |||||
| <ul className="absolute left-0 right-0 z-50 w-full bg-gray-800 border border-gray-600 rounded shadow"> | <ul className="absolute left-0 right-0 z-50 w-full bg-gray-800 border border-gray-600 rounded shadow"> | ||||
| {suggestions.map ((tag, i) => ( | {suggestions.map ((tag, i) => ( | ||||
| <li key={tag.id} | <li key={tag.id} | ||||
| className={`px-3 py-2 cursor-pointer ${ | |||||
| i === activeIndex ? 'bg-blue-600 text-white' : 'hover:bg-gray-700' }`} | |||||
| className={cn ('px-3 py-2 cursor-pointer', | |||||
| (i === activeIndex | |||||
| ? 'bg-blue-600 text-white' | |||||
| : 'hover:bg-gray-700'))} | |||||
| onMouseDown={() => onSelect (tag)} | onMouseDown={() => onSelect (tag)} | ||||
| > | > | ||||
| {tag.name} | {tag.name} | ||||
| @@ -2,8 +2,9 @@ import React, { useEffect, useState } from 'react' | |||||
| import axios from 'axios' | import axios from 'axios' | ||||
| import { Link, useParams } from 'react-router-dom' | import { Link, useParams } from 'react-router-dom' | ||||
| import { API_BASE_URL } from '@/config' | import { API_BASE_URL } from '@/config' | ||||
| import TagSearch from './TagSearch' | |||||
| import SidebarComponent from './layout/SidebarComponent' | |||||
| import TagSearch from '@/components/TagSearch' | |||||
| import SidebarComponent from '@/components/layout/SidebarComponent' | |||||
| import SectionTitle from '@/components/common/SectionTitle' | |||||
| import type { Post, Tag } from '@/types' | import type { Post, Tag } from '@/types' | ||||
| @@ -12,12 +13,6 @@ type TagByCategory = { [key: string]: Tag[] } | |||||
| type Props = { posts: Post[] } | type Props = { posts: Post[] } | ||||
| const tagNameMap: { [key: string]: string } = { | |||||
| general: '一般', | |||||
| deerjikist: 'ニジラー', | |||||
| nico: 'ニコニコタグ' } | |||||
| export default ({ posts }: Props) => { | export default ({ posts }: Props) => { | ||||
| const [tags, setTags] = useState<TagByCategory> ({ }) | const [tags, setTags] = useState<TagByCategory> ({ }) | ||||
| const [tagsCounts, setTagsCounts] = useState<{ [key: number]: number }> ({ }) | const [tagsCounts, setTagsCounts] = useState<{ [key: number]: number }> ({ }) | ||||
| @@ -47,18 +42,20 @@ export default ({ posts }: Props) => { | |||||
| return ( | return ( | ||||
| <SidebarComponent> | <SidebarComponent> | ||||
| <TagSearch /> | <TagSearch /> | ||||
| {['general', 'deerjikist', 'nico'].map (cat => cat in tags && <> | |||||
| <h2>{tagNameMap[cat]}</h2> | |||||
| <ul> | |||||
| {tags[cat].map (tag => ( | |||||
| <li key={tag.id} className="mb-2"> | |||||
| <Link to={`/posts?${ (new URLSearchParams ({ tags: tag.name })).toString () }`} | |||||
| className="text-blue-600 hover:underline"> | |||||
| {tag.name} | |||||
| </Link> | |||||
| <span className="ml-1">{tagsCounts[tag.id]}</span> | |||||
| </li>))} | |||||
| </ul> | |||||
| </>)} | |||||
| <SectionTitle>タグ</SectionTitle> | |||||
| <ul> | |||||
| {['general', 'deerjikist', 'nico'].map (cat => cat in tags && ( | |||||
| <> | |||||
| {tags[cat].map (tag => ( | |||||
| <li key={tag.id} className="mb-1"> | |||||
| <Link to={`/posts?${ (new URLSearchParams ({ tags: tag.name })).toString () }`}> | |||||
| {tag.name} | |||||
| </Link> | |||||
| <span className="ml-1">{tagsCounts[tag.id]}</span> | |||||
| </li>))} | |||||
| </>))} | |||||
| </ul> | |||||
| <SectionTitle>関聯</SectionTitle> | |||||
| <Link>ランダム</Link> | |||||
| </SidebarComponent>) | </SidebarComponent>) | ||||
| } | } | ||||
| @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react' | |||||
| import { Link, useLocation, useNavigate, useParams } from 'react-router-dom' | import { Link, useLocation, useNavigate, useParams } from 'react-router-dom' | ||||
| import SettingsDialogue from './SettingsDialogue' | import SettingsDialogue from './SettingsDialogue' | ||||
| import { Button } from './ui/button' | import { Button } from './ui/button' | ||||
| import clsx from 'clsx' | |||||
| import { cn } from '@/lib/utils' | |||||
| import { WikiIdBus } from '@/lib/eventBus/WikiIdBus' | import { WikiIdBus } from '@/lib/eventBus/WikiIdBus' | ||||
| import type { User } from '@/types' | import type { User } from '@/types' | ||||
| @@ -33,10 +33,10 @@ const TopNav: React.FC = ({ user, setUser }: Props) => { | |||||
| title: string | title: string | ||||
| menu?: Menu | menu?: Menu | ||||
| base?: string }) => ( | base?: string }) => ( | ||||
| <Link to={to} className={clsx ('hover:text-orange-500 h-full flex items-center', | |||||
| (location.pathname.startsWith (base ?? to) | |||||
| ? 'bg-gray-700 px-4 font-bold' | |||||
| : 'px-2'))}> | |||||
| <Link to={to} className={cn ('hover:text-orange-500 h-full flex items-center', | |||||
| (location.pathname.startsWith (base ?? to) | |||||
| ? 'bg-gray-700 px-4 font-bold' | |||||
| : 'px-2'))}> | |||||
| {title} | {title} | ||||
| </Link>) | </Link>) | ||||
| @@ -0,0 +1,9 @@ | |||||
| import React from 'react' | |||||
| type Props = { children: React.ReactNode } | |||||
| export default ({ children }: Props) => ( | |||||
| <div className="max-w-xl mx-auto p-4 space-y-4"> | |||||
| {children} | |||||
| </div>) | |||||
| @@ -0,0 +1,28 @@ | |||||
| import React from 'react' | |||||
| type Props = { children: React.ReactNode | |||||
| checkBox?: { label: string | |||||
| checked: boolean | |||||
| onChange: (event: React.ChangeEvent<HTMLInputElement>) => void } } | |||||
| export default ({ children, checkBox }: Props) => { | |||||
| if (!(checkBox)) | |||||
| { | |||||
| return ( | |||||
| <label className="block font-semibold mb-1"> | |||||
| {children} | |||||
| </label>) | |||||
| } | |||||
| return ( | |||||
| <div className="flex gap-2 mb-1"> | |||||
| <label className="flex-1 block font-semibold">{children}</label> | |||||
| <label className="flex items-center block gap-1"> | |||||
| <input type="checkbox" | |||||
| checked={checkBox.checked} | |||||
| onChange={checkBox.onChange} /> | |||||
| {checkBox.label} | |||||
| </label> | |||||
| </div>) | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| import React from 'react' | |||||
| type Props = { children: React.ReactNode } | |||||
| export default ({ children }: Props) => ( | |||||
| <h1 className="text-2xl font-bold mb-2"> | |||||
| {children} | |||||
| </h1>) | |||||
| @@ -0,0 +1,9 @@ | |||||
| import React from 'react' | |||||
| type Props = { children: React.ReactNode } | |||||
| export default ({ children }: Props) => ( | |||||
| <h2 className="text-xl my-4"> | |||||
| {children} | |||||
| </h2>) | |||||
| @@ -0,0 +1,9 @@ | |||||
| import React from 'react' | |||||
| type Props = { children: React.ReactNode } | |||||
| export default ({ children }: Props) => ( | |||||
| <h3 className="my-2"> | |||||
| {children} | |||||
| </h3>) | |||||
| @@ -1,4 +1,5 @@ | |||||
| import React, { useState } from 'react' | import React, { useState } from 'react' | ||||
| import { cn } from '@/lib/utils' | |||||
| type TabProps = { name: string | type TabProps = { name: string | ||||
| init?: boolean | init?: boolean | ||||
| @@ -6,7 +7,7 @@ type TabProps = { name: string | |||||
| type Props = { children: React.ReactElement<{ name: string }>[] } | type Props = { children: React.ReactElement<{ name: string }>[] } | ||||
| export const Tab = ({ children }: TabProps) => children | |||||
| export const Tab = ({ children }: TabProps) => <>{children}</> | |||||
| export default ({ children }: Props) => { | export default ({ children }: Props) => { | ||||
| @@ -23,7 +24,7 @@ export default ({ children }: Props) => { | |||||
| {tabs.map ((tab, i) => ( | {tabs.map ((tab, i) => ( | ||||
| <a key={i} | <a key={i} | ||||
| href="#" | href="#" | ||||
| className={`text-blue-400 hover:underline ${ i === current ? 'font-bold' : '' }`} | |||||
| className={cn (i === current && 'font-bold')} | |||||
| onClick={ev => { | onClick={ev => { | ||||
| ev.preventDefault () | ev.preventDefault () | ||||
| setCurrent (i) | setCurrent (i) | ||||
| @@ -6,6 +6,7 @@ import axios from 'axios' | |||||
| import { API_BASE_URL, SITE_TITLE } from '@/config' | import { API_BASE_URL, SITE_TITLE } from '@/config' | ||||
| import MainArea from '@/components/layout/MainArea' | import MainArea from '@/components/layout/MainArea' | ||||
| import { WikiIdBus } from '@/lib/eventBus/WikiIdBus' | import { WikiIdBus } from '@/lib/eventBus/WikiIdBus' | ||||
| import PageTitle from '@/components/common/PageTitle' | |||||
| import type { WikiPage } from '@/types' | import type { WikiPage } from '@/types' | ||||
| @@ -45,20 +46,18 @@ export default () => { | |||||
| {(wikiPage && version) && ( | {(wikiPage && version) && ( | ||||
| <div className="text-sm flex gap-3 items-center justify-center border border-gray-700 rounded px-2 py-1 mb-4"> | <div className="text-sm flex gap-3 items-center justify-center border border-gray-700 rounded px-2 py-1 mb-4"> | ||||
| {wikiPage.pred ? ( | {wikiPage.pred ? ( | ||||
| <Link to={`/wiki/${ title }?version=${ wikiPage.pred }`} | |||||
| className="text-blue-400 hover:underline"> | |||||
| < 前 | |||||
| </Link>) : <>< 前</>} | |||||
| <Link to={`/wiki/${ title }?version=${ wikiPage.pred }`}> | |||||
| < 古 | |||||
| </Link>) : <>(最古)</>} | |||||
| <span>{wikiPage.updated_at}</span> | <span>{wikiPage.updated_at}</span> | ||||
| {wikiPage.succ ? ( | {wikiPage.succ ? ( | ||||
| <Link to={`/wiki/${ title }?version=${ wikiPage.succ }`} | |||||
| className="text-blue-400 hover:underline"> | |||||
| 後 > | |||||
| </Link>) : <>後 ></>} | |||||
| <Link to={`/wiki/${ title }?version=${ wikiPage.succ }`}> | |||||
| 新 > | |||||
| </Link>) : <>(最新)</>} | |||||
| </div>)} | </div>)} | ||||
| <h1>{title}</h1> | |||||
| <PageTitle>{title}</PageTitle> | |||||
| <div className="prose mx-auto p-4"> | <div className="prose mx-auto p-4"> | ||||
| {wikiPage === undefined ? 'Loading...' : ( | {wikiPage === undefined ? 'Loading...' : ( | ||||
| <> | <> | ||||
| @@ -1,7 +1,9 @@ | |||||
| import axios from 'axios' | |||||
| import { useEffect, useState } from 'react' | import { useEffect, useState } from 'react' | ||||
| import { Helmet } from 'react-helmet' | import { Helmet } from 'react-helmet' | ||||
| import { Link, useLocation, useParams } from 'react-router-dom' | import { Link, useLocation, useParams } from 'react-router-dom' | ||||
| import axios from 'axios' | |||||
| import PageTitle from '@/components/common/PageTitle' | |||||
| import MainArea from '@/components/layout/MainArea' | import MainArea from '@/components/layout/MainArea' | ||||
| import { API_BASE_URL, SITE_TITLE } from '@/config' | import { API_BASE_URL, SITE_TITLE } from '@/config' | ||||
| @@ -29,7 +31,7 @@ export default () => { | |||||
| <Helmet> | <Helmet> | ||||
| <title>{`Wiki 差分: ${ diff?.title } | ${ SITE_TITLE }`}</title> | <title>{`Wiki 差分: ${ diff?.title } | ${ SITE_TITLE }`}</title> | ||||
| </Helmet> | </Helmet> | ||||
| <h1>{diff?.title}</h1> | |||||
| <PageTitle>{diff?.title}</PageTitle> | |||||
| <div className="prose mx-auto p-4"> | <div className="prose mx-auto p-4"> | ||||
| {diff ? ( | {diff ? ( | ||||
| diff.diff.map (d => ( | diff.diff.map (d => ( | ||||
| @@ -44,8 +44,7 @@ export default () => { | |||||
| </Link>)} | </Link>)} | ||||
| </td> | </td> | ||||
| <td className="p-2"> | <td className="p-2"> | ||||
| <Link to={`/wiki/${ encodeURIComponent (change.wiki_page.title) }?version=${ change.sha }`} | |||||
| className="text-blue-400 hover:underline"> | |||||
| <Link to={`/wiki/${ encodeURIComponent (change.wiki_page.title) }?version=${ change.sha }`}> | |||||
| {change.wiki_page.title} | {change.wiki_page.title} | ||||
| </Link> | </Link> | ||||
| </td> | </td> | ||||
| @@ -63,8 +62,7 @@ export default () => { | |||||
| }) ()} | }) ()} | ||||
| </td> | </td> | ||||
| <td className="p-2"> | <td className="p-2"> | ||||
| <Link to={`/users/${ change.user.id }`} | |||||
| className="text-blue-400 hover:underline"> | |||||
| <Link to={`/users/${ change.user.id }`}> | |||||
| {change.user.name} | {change.user.name} | ||||
| </Link> | </Link> | ||||
| <br /> | <br /> | ||||
| @@ -4,6 +4,7 @@ import { Link } from 'react-router-dom' | |||||
| import axios from 'axios' | import axios from 'axios' | ||||
| import MainArea from '@/components/layout/MainArea' | import MainArea from '@/components/layout/MainArea' | ||||
| import { API_BASE_URL, SITE_TITLE } from '@/config' | import { API_BASE_URL, SITE_TITLE } from '@/config' | ||||
| import SectionTitle from '@/components/common/SectionTitle' | |||||
| import type { Category, WikiPage } from '@/types' | import type { Category, WikiPage } from '@/types' | ||||
| @@ -34,7 +35,7 @@ export default () => { | |||||
| <title>{`Wiki | ${ SITE_TITLE }`}</title> | <title>{`Wiki | ${ SITE_TITLE }`}</title> | ||||
| </Helmet> | </Helmet> | ||||
| <div className="max-w-xl"> | <div className="max-w-xl"> | ||||
| <h2 className="text-xl mb-4">Wiki</h2> | |||||
| <SectionTitle className="text-xl mb-4">Wiki</SectionTitle> | |||||
| <form onSubmit={handleSearch} className="space-y-2"> | <form onSubmit={handleSearch} className="space-y-2"> | ||||
| {/* タイトル */} | {/* タイトル */} | ||||
| <div> | <div> | ||||
| @@ -76,8 +77,7 @@ export default () => { | |||||
| {results.map (page => ( | {results.map (page => ( | ||||
| <tr key={page.id}> | <tr key={page.id}> | ||||
| <td className="p-2"> | <td className="p-2"> | ||||
| <Link to={`/wiki/${ encodeURIComponent (page.title) }`} | |||||
| className="text-blue-400 hover:underline"> | |||||
| <Link to={`/wiki/${ encodeURIComponent (page.title) }`}> | |||||
| {page.title} | {page.title} | ||||
| </Link> | </Link> | ||||
| </td> | </td> | ||||
| @@ -65,7 +65,14 @@ export default ({ user }: Props) => { | |||||
| setEditing (true) | setEditing (true) | ||||
| }, [editing]) | }, [editing]) | ||||
| const url = post ? new URL (post.url) : undefined | |||||
| const url = post ? new URL (post.url) : null | |||||
| const nicoFlg = url?.hostname.split ('.').slice (-2).join ('.') === 'nicovideo.jp' | |||||
| const videoId = (nicoFlg | |||||
| ? url.pathname.match (/(?<=\/watch\/)[a-zA-Z0-9]+?(?=\/|$)/)[0] | |||||
| : '') | |||||
| const viewedClass = (post?.viewed | |||||
| ? 'bg-blue-600 hover:bg-blue-700' | |||||
| : 'bg-gray-500 hover:bg-gray-600') | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| @@ -76,23 +83,15 @@ export default ({ user }: Props) => { | |||||
| <MainArea> | <MainArea> | ||||
| {post | {post | ||||
| ? ( | ? ( | ||||
| <div className="p-4"> | |||||
| {(() => { | |||||
| if (url.hostname.split ('.').slice (-2).join ('.') === 'nicovideo.jp') | |||||
| { | |||||
| return ( | |||||
| <NicoViewer | |||||
| id={url.pathname.match ( | |||||
| /(?<=\/watch\/)[a-zA-Z0-9]+?(?=\/|$)/)[0]} | |||||
| width="640" | |||||
| height="360" />) | |||||
| } | |||||
| else | |||||
| return <img src={post.thumbnail} alt={post.url} className="mb-4 w-full" /> | |||||
| }) ()} | |||||
| <> | |||||
| {nicoFlg | |||||
| ? ( | |||||
| <NicoViewer id={videoId} | |||||
| width="640" | |||||
| height="360" />) | |||||
| : <img src={post.thumbnail} alt={post.url} className="mb-4 w-full" />} | |||||
| <Button onClick={changeViewedFlg} | <Button onClick={changeViewedFlg} | ||||
| className={cn ('text-white', | |||||
| post.viewed ? 'bg-blue-600 hover:bg-blue-700' : 'bg-gray-500 hover:bg-gray-600')}> | |||||
| className={cn ('text-white', viewedClass)}> | |||||
| {post.viewed ? '閲覧済' : '未閲覧'} | {post.viewed ? '閲覧済' : '未閲覧'} | ||||
| </Button> | </Button> | ||||
| <TabGroup> | <TabGroup> | ||||
| @@ -105,7 +104,7 @@ export default ({ user }: Props) => { | |||||
| }} /> | }} /> | ||||
| </Tab>} | </Tab>} | ||||
| </TabGroup> | </TabGroup> | ||||
| </div>) | |||||
| </>) | |||||
| : 'Loading...'} | : 'Loading...'} | ||||
| </MainArea> | </MainArea> | ||||
| </>) | </>) | ||||
| @@ -8,6 +8,9 @@ import { Button } from '@/components/ui/button' | |||||
| import { toast } from '@/components/ui/use-toast' | import { toast } from '@/components/ui/use-toast' | ||||
| import { cn } from '@/lib/utils' | import { cn } from '@/lib/utils' | ||||
| import MainArea from '@/components/layout/MainArea' | import MainArea from '@/components/layout/MainArea' | ||||
| import Form from '@/components/common/Form' | |||||
| import PageTitle from '@/components/common/PageTitle' | |||||
| import Label from '@/components/common/Label' | |||||
| import type { Post, Tag } from '@/types' | import type { Post, Tag } from '@/types' | ||||
| @@ -115,12 +118,12 @@ export default () => { | |||||
| <Helmet> | <Helmet> | ||||
| <title>{`広場に投稿を追加 | ${ SITE_TITLE }`}</title> | <title>{`広場に投稿を追加 | ${ SITE_TITLE }`}</title> | ||||
| </Helmet> | </Helmet> | ||||
| <div className="max-w-xl mx-auto p-4 space-y-4"> | |||||
| <h1 className="text-2xl font-bold mb-2">広場に投稿を追加する</h1> | |||||
| <Form> | |||||
| <PageTitle>広場に投稿を追加する</PageTitle> | |||||
| {/* URL */} | {/* URL */} | ||||
| <div> | <div> | ||||
| <label className="block font-semibold mb-1">URL</label> | |||||
| <Label>URL</Label> | |||||
| <input type="text" | <input type="text" | ||||
| placeholder="例:https://www.nicovideo.jp/watch/..." | placeholder="例:https://www.nicovideo.jp/watch/..." | ||||
| value={url} | value={url} | ||||
| @@ -131,15 +134,12 @@ export default () => { | |||||
| {/* タイトル */} | {/* タイトル */} | ||||
| <div> | <div> | ||||
| <div className="flex gap-2 mb-1"> | |||||
| <label className="flex-1 block font-semibold">タイトル</label> | |||||
| <label className="flex items-center block gap-1"> | |||||
| <input type="checkbox" | |||||
| checked={titleAutoFlg} | |||||
| onChange={e => setTitleAutoFlg (e.target.checked)} /> | |||||
| 自動 | |||||
| </label> | |||||
| </div> | |||||
| <Label checkBox={{ | |||||
| label: '自動', | |||||
| checked: titleAutoFlg, | |||||
| onChange: ev => setTitleAutoFlg (ev.target.checked)}}> | |||||
| タイトル | |||||
| </Label> | |||||
| <input type="text" | <input type="text" | ||||
| className="w-full border rounded p-2" | className="w-full border rounded p-2" | ||||
| value={title} | value={title} | ||||
| @@ -150,15 +150,12 @@ export default () => { | |||||
| {/* サムネール */} | {/* サムネール */} | ||||
| <div> | <div> | ||||
| <div className="flex gap-2 mb-1"> | |||||
| <label className="block font-semibold flex-1">サムネール</label> | |||||
| <label className="flex items-center gap-1"> | |||||
| <input type="checkbox" | |||||
| checked={thumbnailAutoFlg} | |||||
| onChange={e => setThumbnailAutoFlg (e.target.checked)} /> | |||||
| 自動 | |||||
| </label> | |||||
| </div> | |||||
| <Label checkBox={{ | |||||
| label: '自動', | |||||
| checked: thumbnailAutoFlg, | |||||
| onChange: ev => setThumbnailAutoFlg (ev.target.checked)}}> | |||||
| サムネール | |||||
| </Label> | |||||
| {thumbnailAutoFlg | {thumbnailAutoFlg | ||||
| ? (thumbnailLoading | ? (thumbnailLoading | ||||
| ? <p className="text-gray-500 text-sm">Loading...</p> | ? <p className="text-gray-500 text-sm">Loading...</p> | ||||
| @@ -185,7 +182,7 @@ export default () => { | |||||
| {/* タグ */} | {/* タグ */} | ||||
| <div> | <div> | ||||
| <label className="block font-semibold">タグ</label> | |||||
| <Label>タグ</Label> | |||||
| <select multiple | <select multiple | ||||
| value={tagIds.map (String)} | value={tagIds.map (String)} | ||||
| onChange={e => { | onChange={e => { | ||||
| @@ -201,11 +198,11 @@ export default () => { | |||||
| </div> | </div> | ||||
| {/* 送信 */} | {/* 送信 */} | ||||
| <button onClick={handleSubmit} | |||||
| <Button onClick={handleSubmit} | |||||
| className="px-4 py-2 bg-blue-600 text-white rounded disabled:bg-gray-400" | className="px-4 py-2 bg-blue-600 text-white rounded disabled:bg-gray-400" | ||||
| disabled={titleLoading || thumbnailLoading}> | disabled={titleLoading || thumbnailLoading}> | ||||
| 追加 | 追加 | ||||
| </button> | |||||
| </div> | |||||
| </Button> | |||||
| </Form> | |||||
| </MainArea>) | </MainArea>) | ||||
| } | } | ||||