ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

160 lines
5.6 KiB

  1. import { AnimatePresence, LayoutGroup, motion } from 'framer-motion'
  2. import { useEffect, useState } from 'react'
  3. import { BrowserRouter,
  4. Navigate,
  5. Route,
  6. Routes,
  7. useLocation } from 'react-router-dom'
  8. import RouteBlockerOverlay from '@/components/RouteBlockerOverlay'
  9. import TopNav from '@/components/TopNav'
  10. import DialogueProvider from '@/components/dialogues/DialogueProvider'
  11. import { Toaster } from '@/components/ui/toaster'
  12. import { apiPost, isApiError } from '@/lib/api'
  13. import DeerjikistDetailPage from '@/pages/deerjikists/DeerjikistDetailPage'
  14. import MaterialBasePage from '@/pages/materials/MaterialBasePage'
  15. import MaterialDetailPage from '@/pages/materials/MaterialDetailPage'
  16. import MaterialListPage from '@/pages/materials/MaterialListPage'
  17. import MaterialNewPage from '@/pages/materials/MaterialNewPage'
  18. // import MaterialSearchPage from '@/pages/materials/MaterialSearchPage'
  19. import MorePage from '@/pages/MorePage'
  20. import NicoTagListPage from '@/pages/tags/NicoTagListPage'
  21. import NotFound from '@/pages/NotFound'
  22. import TOSPage from '@/pages/TOSPage.mdx'
  23. import PostDetailPage from '@/pages/posts/PostDetailPage'
  24. import PostHistoryPage from '@/pages/posts/PostHistoryPage'
  25. import PostListPage from '@/pages/posts/PostListPage'
  26. import PostNewPage from '@/pages/posts/PostNewPage'
  27. import PostSearchPage from '@/pages/posts/PostSearchPage'
  28. import ServiceUnavailable from '@/pages/ServiceUnavailable'
  29. import SettingPage from '@/pages/users/SettingPage'
  30. import TagDetailPage from '@/pages/tags/TagDetailPage'
  31. import TagHistoryPage from '@/pages/tags/TagHistoryPage'
  32. import TagListPage from '@/pages/tags/TagListPage'
  33. import TheatreDetailPage from '@/pages/theatres/TheatreDetailPage'
  34. import WikiDetailPage from '@/pages/wiki/WikiDetailPage'
  35. import WikiDiffPage from '@/pages/wiki/WikiDiffPage'
  36. import WikiEditPage from '@/pages/wiki/WikiEditPage'
  37. import WikiHistoryPage from '@/pages/wiki/WikiHistoryPage'
  38. import WikiNewPage from '@/pages/wiki/WikiNewPage'
  39. import WikiSearchPage from '@/pages/wiki/WikiSearchPage'
  40. import type { Dispatch, FC, SetStateAction } from 'react'
  41. import type { User } from '@/types'
  42. const RouteTransitionWrapper = ({ user, setUser }: {
  43. user: User | null
  44. setUser: Dispatch<SetStateAction<User | null>> }) => {
  45. const location = useLocation ()
  46. return (
  47. <AnimatePresence mode="wait">
  48. <Routes location={location}>
  49. <Route path="/" element={<Navigate to="/posts" replace/>}/>
  50. <Route path="/posts" element={<PostListPage/>}/>
  51. <Route path="/posts/new" element={<PostNewPage user={user}/>}/>
  52. <Route path="/posts/search" element={<PostSearchPage/>}/>
  53. <Route path="/posts/:id" element={<PostDetailRoute user={user}/>}/>
  54. <Route path="/posts/changes" element={<PostHistoryPage/>}/>
  55. <Route path="/tags" element={<TagListPage/>}/>
  56. <Route path="/tags/:id" element={<TagDetailPage/>}/>
  57. <Route path="/tags/:id/deerjikists" element={<DeerjikistDetailPage/>}/>
  58. <Route path="/tags/nico" element={<NicoTagListPage user={user}/>}/>
  59. <Route path="/tags/changes" element={<TagHistoryPage/>}/>
  60. <Route path="/theatres/:id" element={<TheatreDetailPage/>}/>
  61. <Route path="/materials" element={<MaterialBasePage/>}>
  62. <Route index element={<MaterialListPage/>}/>
  63. <Route path="new" element={<MaterialNewPage/>}/>
  64. <Route path=":id" element ={<MaterialDetailPage/>}/>
  65. </Route>
  66. {/* <Route path="/materials/search" element={<MaterialSearchPage/>}/> */}
  67. <Route path="/wiki" element={<WikiSearchPage/>}/>
  68. <Route path="/wiki/:title" element={<WikiDetailPage/>}/>
  69. <Route path="/wiki/new" element={<WikiNewPage user={user}/>}/>
  70. <Route path="/wiki/:id/edit" element={<WikiEditPage user={user}/>}/>
  71. <Route path="/wiki/:id/diff" element={<WikiDiffPage/>}/>
  72. <Route path="/wiki/changes" element={<WikiHistoryPage/>}/>
  73. <Route path="/users/settings" element={<SettingPage user={user} setUser={setUser}/>}/>
  74. <Route path="/settings" element={<Navigate to="/users/settings" replace/>}/>
  75. <Route path="/tos" element={<TOSPage/>}/>
  76. <Route path="/more" element={<MorePage/>}/>
  77. <Route path="*" element={<NotFound/>}/>
  78. </Routes>
  79. </AnimatePresence>)
  80. }
  81. const PostDetailRoute = ({ user }: { user: User | null }) => {
  82. const location = useLocation ()
  83. const key = location.pathname
  84. return <PostDetailPage key={key} user={user}/>
  85. }
  86. export default (() => {
  87. const [user, setUser] = useState<User | null> (null)
  88. const [status, setStatus] = useState (200)
  89. useEffect (() => {
  90. const createUser = async () => {
  91. const data = await apiPost<{ code: string; user: User }> ('/users')
  92. if (data.code)
  93. {
  94. localStorage.setItem ('user_code', data.code)
  95. setUser (data.user)
  96. }
  97. }
  98. const code = localStorage.getItem ('user_code')
  99. if (code)
  100. {
  101. void (async () => {
  102. try
  103. {
  104. const data = await apiPost<{ valid: boolean; user: User }> ('/users/verify', { code })
  105. if (data.valid)
  106. setUser (data.user)
  107. else
  108. await createUser ()
  109. }
  110. catch (err)
  111. {
  112. if (isApiError (err))
  113. setStatus (err.response?.status ?? 200)
  114. }
  115. }) ()
  116. }
  117. else
  118. createUser ()
  119. }, [])
  120. switch (status)
  121. {
  122. case 503:
  123. return <ServiceUnavailable/>
  124. }
  125. return (
  126. <>
  127. <RouteBlockerOverlay/>
  128. <BrowserRouter>
  129. <DialogueProvider>
  130. <LayoutGroup>
  131. <motion.div
  132. layout="position"
  133. transition={{ layout: { duration: .2, ease: 'easeOut' } }}
  134. className="flex flex-col h-dvh w-full overflow-y-hidden">
  135. <TopNav user={user}/>
  136. <RouteTransitionWrapper user={user} setUser={setUser}/>
  137. </motion.div>
  138. </LayoutGroup>
  139. <Toaster/>
  140. </DialogueProvider>
  141. </BrowserRouter>
  142. </>)
  143. }) satisfies FC